LangChain多模态输入与自定义输出

多模态数据输入

这里我们演示如何将多模态输入直接传递给模型。我们目前期望所有输入都以与OpenAI 期望的格式相同的格式传递。对于支持多模态输入的其他模型提供者,我们在类中添加了逻辑以转换为预期格式。

接入豆包

安装sdk

pip install 'volcengine-python-sdk[ark]'

豆包原生写法

python 复制代码
import os
from volcenginesdkarkruntime import Ark

client = Ark(
    base_url='https://ark.cn-beijing.volces.com/api/v3',
    api_key=os.getenv('ARK_API_KEY'),
)

response = client.responses.create(
    model="doubao-seed-2-0-lite-260215",
    input=[
        {
            "role": "user",
            "content": [
                {
                    "type": "input_image",
                    "image_url": "https://ark-project.tos-cn-beijing.volces.com/doc_image/ark_demo_img_1.png"
                },
                {
                    "type": "input_text",
                    "text": "支持输入图片的模型系列是哪个?"
                },
            ],
        }
    ]
)

print(response)

LangChain写法

python 复制代码
import os
import base64
from pathlib import Path

from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI


llm = ChatOpenAI(
    model="doubao-seed-2-0-lite-260215",
    openai_api_base="https://ark.cn-beijing.volces.com/api/v3",
    openai_api_key=os.getenv("ARK_API_KEY"),
)

image_path = Path("./蓝天白云.jpg")
with image_path.open("rb") as f:
    image_data = f.read()
    base64_image = base64.b64encode(image_data).decode("utf-8")

message = HumanMessage(
    content=[
        # {"type": "image_url", "image_url": {"url": "https://ark-project.tos-cn-beijing.volces.com/doc_image/ark_demo_img_1.png"}},
        # {"type": "image_url", "image_url": {"url": "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"}},
        {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}},
        # {"type": "text", "text": "支持输入图片的模型系列是哪个?"},
        # {"type": "text", "text": "图片中的文字是啥?"},
        {"type": "text", "text": "图片中的天气是啥?"},
    ]
)

response = llm.invoke([message])
print(response.content)

工具调用

这里我们演示如何将多模态输入直接传递给模型。我们目前期望所有输入都以与OpenAI 期望的格式相同的格式传递。对于支持多模态输入的其他模型提供者,我们在类中添加了逻辑以转换为预期格式。

在这个例子中,我们将要求模型描述一幅图像。

python 复制代码
import os
import base64
from pathlib import Path
from typing import Literal

from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool


@tool
def weather_tool(weather: Literal["多云的", "多雨的", "晴朗的", "下雪的"]) -> None:
    """Describe the weather"""
    pass    


llm = ChatOpenAI(
    model="doubao-seed-2-0-lite-260215",
    openai_api_base="https://ark.cn-beijing.volces.com/api/v3",
    openai_api_key=os.getenv("ARK_API_KEY"),
)
llm_with_tools = llm.bind_tools([weather_tool])

image_path = Path("./蓝天白云.jpg")
with image_path.open("rb") as f:
    image_data = f.read()
    base64_image = base64.b64encode(image_data).decode("utf-8")

message = HumanMessage(
    content=[
        # {"type": "image_url", "image_url": {"url": "https://ark-project.tos-cn-beijing.volces.com/doc_image/ark_demo_img_1.png"}},
        # {"type": "image_url", "image_url": {"url": "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"}},
        {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}},
        # {"type": "text", "text": "支持输入图片的模型系列是哪个?"},
        # {"type": "text", "text": "图片中的文字是啥?"},
        {"type": "text", "text": "图片中的天气是啥?"},
    ]
)

response = llm_with_tools.invoke([message])
print(response.tool_calls)

自定义输出:JSON、XML、YAML

如何解析JSON输出

虽然一些模型提供商支持内置的方法返回结构化输出,但并非所有都支持。我们可以使用输出解析器来帮助用户通过提示指定任意的 JSON 模式,查询符合该模式的模型输出,最后将该模式解析为 JSON。

请记住,大型语言模型是有泄漏的抽象!您必须使用具有足够容量的大型语言模型来生成格式良好的 JSON。JsonOutputParser 是一个内置选项,用于提示并解析 JSON 输出。虽然它在功能上类似于 PydanticOutputParser,但它还支持流式返回部分 JSON 对象。

以下是如何将其与Pydantic一起使用以方便地声明预期模式的示例:

python 复制代码
import os

from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field


model = ChatOpenAI(
    model="doubao-seed-2-0-lite-260215",
    openai_api_base="https://ark.cn-beijing.volces.com/api/v3",
    openai_api_key=os.getenv("ARK_API_KEY"),
)

# 定义您期望的数据结构
class Joke(BaseModel):
    setup: str = Field(description="设置笑话的问题")
    punchline: str = Field(description="解决笑话的答案")


# 还有一个用于提示语言模型填充数据结构的查询意图
joke_query = "告诉我一个笑话"
# 设置解析器 + 将指令注入提示模版
parser = JsonOutputParser(pydantic_object=Joke)

# 构造一个可复用的提示词模版,其中既有固定文本,也有运行时填充的变量
prompt = PromptTemplate(
    # 模版正文:固定指令回答用户的问题,format_instructions: 由解析器给出的输出格式的要求,query:用户实际问题
    template="回答用户的查询。\n{format_instructions}\n{query}",
    # 声明这个模版在调用时必须传入的动态变量
    input_variables=["query"],
    # 预先绑定部分变量,相当于给模版做了默认填充,这里把 format_instructions 固定成 parser.get_format_instructions() 的结果(通常是请输出JSON,字段包含,这类格式约束)
    # 好处是每次调用时不用重复传递这个变量,只需要传递 query 就行
    partial_variables={"format_instructions": parser.get_format_instructions()},
)

chain = prompt | model | parser
response = chain.invoke({"query": joke_query})
print(response)

# 流式输出
# for chunk in chain.stream({"query": joke_query}):
#    print(chunk)

如何解析XML输出

下面使用XMLOutputParser来提示模型生成XML输出,然后将该输出解析为可用的格式。

我们可以使用XMLOutputParser将默认的格式指令添加到提示中,并将输出的XML解析为字典:

安装xml依赖:pip install defusedxml

python 复制代码
import os

# from langchain_core.output_parsers import JsonOutputParser
from langchain_core.output_parsers import XMLOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field


model = ChatOpenAI(
    model="doubao-seed-2-0-lite-260215",
    openai_api_base="https://ark.cn-beijing.volces.com/api/v3",
    openai_api_key=os.getenv("ARK_API_KEY"),
)

# 定义您期望的数据结构
class Joke(BaseModel):
    setup: str = Field(description="设置笑话的问题")
    punchline: str = Field(description="解决笑话的答案")


# 还有一个用于提示语言模型填充数据结构的查询意图
joke_query = "告诉我一个笑话"
# 设置解析器 + 将指令注入提示模版
# parser = JsonOutputParser(pydantic_object=Joke)
parser = XMLOutputParser()

# 构造一个可复用的提示词模版,其中既有固定文本,也有运行时填充的变量
prompt = PromptTemplate(
    # 模版正文:固定指令回答用户的问题,format_instructions: 由解析器给出的输出格式的要求,query:用户实际问题
    template="回答用户的查询。\n{format_instructions}\n{query}",
    # 声明这个模版在调用时必须传入的动态变量
    input_variables=["query"],
    # 预先绑定部分变量,相当于给模版做了默认填充,这里把 format_instructions 固定成 parser.get_format_instructions() 的结果(通常是请输出JSON,字段包含,这类格式约束)
    # 好处是每次调用时不用重复传递这个变量,只需要传递 query 就行
    partial_variables={"format_instructions": parser.get_format_instructions()},
)

chain = prompt | model 

response = chain.invoke({"query": joke_query})
xml_response = parser.parse(response.content)
print(xml_response)

我们还可以添加一些标签以根据我们的需求定制输出。您可以在提示的其他部分中尝试添加自己的格式提示,以增强或替换默认指令:

python 复制代码
parser = XMLOutputParser(tags=["movies", "actor", "film", "name", "genre"])

输出结果:

text 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<movies>
    <actor>周星驰</actor>
    <film>
        <name>新喜剧之王</name>
        <genre>剧情, 喜剧</genre>
    </film>
    <film>
        <name>西游伏妖篇</name>
        <genre>喜剧, 奇幻, 动作</genre>
    </film>
    <film>
        <name>美人鱼</name>
        <genre>喜剧, 爱情, 奇幻</genre>
    </film>
    <film>
        <name>西游降魔篇</name>
        <genre>喜剧, 奇幻, 冒险</genre>
    </film>
    <film>
        <name>长江七号</name>
        <genre>喜剧, 科幻, 家庭</genre>
    </film>
</movies>

如何解析YAML输出

来自不同提供商的大型语言模型(LLMs)通常根据它们训练的具体数据具有不同的优势。这也意味着有些模型在生成 JSON 以外的格式输出方面可能更"优秀"和可靠。

这个输出解析器允许用户指定任意模式,并查询符合该模式的 LLMS 输出,使用 YAML 格式化他们的响应。

我们使用Pydantic与YamlOutputParser来声明我们的数据模型,并为模型提供更多关于应生成何种类型 YAML 的上下文信息:

python 复制代码
import os
import yaml

from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI


model = ChatOpenAI(
    model="doubao-seed-2-0-lite-260215",
    openai_api_base="https://ark.cn-beijing.volces.com/api/v3",
    openai_api_key=os.getenv("ARK_API_KEY"),
)

# 查询意图
joke_query = "生成周星驰的简化作品电影列表,按照最新的时间降序"

# 由于 LangChain 暂无内置 YAMLOutputParser,这里直接用提示词约束 YAML。
format_instructions = """
请严格只输出 YAML,不要输出 Markdown 代码块,不要输出额外解释文本。
YAML 根节点必须是 movies(列表),每个元素包含字段:
- name: 电影名(字符串)
- year: 上映年份(整数)
- genre: 类型(字符串)
并按 year 降序排列。
""".strip()

# 构造可复用提示词模板
prompt = PromptTemplate(
    template="回答用户的查询。\n{format_instructions}\n{query}",
    input_variables=["query"],
    partial_variables={"format_instructions": format_instructions},
)

chain = prompt | model

response = chain.invoke({"query": joke_query})
yaml_text = response.content

print("=== YAML 原始输出 ===")
print(yaml_text)

parsed = yaml.safe_load(yaml_text)

print("\n=== Python 解析结果 ===")
print(parsed)
相关推荐
Coder小相3 小时前
环境搭建与第一个Agent初体验
人工智能·langchain·ai编程
abigale034 小时前
LangChain 实践2 增强版智能知识库&结构化输出问答器
langchain·runnable·lcel·runnablelambda
Artech4 小时前
[对比学习LangChain和MAF-04]针对消息的设计
ai·langchain·agent·message·maf
Rsingstarzengjx4 小时前
LangChain 是什么
langchain
wuxinyan1235 小时前
工业级大模型学习之路025:问题解决-检索质量全为0
人工智能·python·学习·langchain
wuxinyan1231 天前
工业级大模型学习之路023:LangChain零基础入门教程(第六篇):重排序与高级检索策略
人工智能·python·学习·langchain
abigale031 天前
LangChain 实践 极简个人知识库问答机器人&自定义大模型封装+通用对话链
langchain·prompt·rag·lcel
njsgcs1 天前
那langchain的reAct是怎么实现的
人工智能·langchain
swipe1 天前
Elasticsearch 全文检索工程教程:倒排索引、IK 分词器与 BM25 从原理到落地
面试·langchain·llm