ChatModel 与 Prompt

模型是对接口,Prompt 是入口。两者配合好,LLM 输出质量提升 50%。


ChatModel 统一接口

LangChain 提供统一的 ChatModel 接口,一次代码切换任意模型:

1
2
3
4
5
6
7
8
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
from langchain_ollama import ChatOllama

# 切换模型只需改这一行
llm = ChatOpenAI(model="gpt-4o") # OpenAI
# llm = ChatAnthropic(model="claude-3-5-sonnet") # Claude
# llm = ChatOllama(model="llama3.2") # Ollama

核心方法

1
2
3
4
5
response = llm.invoke("你好")                    # 同步调用
response = await llm.ainvoke("你好") # 异步调用
for chunk in llm.stream("写一首诗"): # 流式输出
print(chunk)
results = llm.batch(["你好", "再见"]) # 批量调用

返回格式

1
2
3
4
5
6
7
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage

# invoke 返回 AIMessage
response = llm.invoke("用 Python 写一个快排")
print(type(response)) # AIMessage
print(response.content) # 文本内容
print(response.response_metadata) # 元数据(token 使用量等)

Prompt 模板化

ChatPromptTemplate

1
2
3
4
5
6
7
8
9
10
11
12
from langchain_core.prompts import ChatPromptTemplate

# 方式1:从消息列表创建
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个{role}助手,擅长{skill}"),
("human", "{question}")
])

# 方式2:从模板字符串创建
prompt = ChatPromptTemplate.from_template(
"用{language}实现{功能},代码要简洁"
)

渲染后的消息格式

1
2
3
4
5
6
7
8
9
10
# 渲染后得到消息列表(可用于多模态等场景)
messages = prompt.format_messages(
role="编程",
skill="算法",
language="Python",
功能="排序"
)
print(messages)
# [SystemMessage(content='你是一个编程助手,擅长算法'),
# HumanMessage(content='用Python实现排序,代码要简洁')]

Few-shot Prompt

提供示例让模型学习输出格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from langchain_core.prompts import FewShotChatMessagePromptTemplate

examples = [
{"input": "苹果是什么", "output": "水果"},
{"input": "胡萝卜是什么", "output": "蔬菜"},
{"input": "牛肉是什么", "output": "肉类"},
]

example_prompt = ChatPromptTemplate.from_messages([
("human", "{input}"),
("ai", "{output}")
])

few_shot_prompt = FewShotChatMessagePromptTemplate(
examples=examples,
example_prompt=example_prompt
)

final_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个分类助手"),
few_shot_prompt, # 示例被插入到这里
("human", "{input}")
])

部分填充模板

1
2
3
4
5
6
7
8
9
10
11
from langchain_core.prompts import ChatPromptTemplate

# 先填充部分变量
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个{agent_role}助手"),
("human", "{user_question}")
])

# 使用 partial 预填充不常变化的变量
system_prompt_filled = prompt.partial(agent_role="代码审查")
# 现在调用时只需提供 user_question

Output Parser(输出解析)

将 LLM 的自由文本输出转换为结构化数据:

1. CommaSeparatedListOutputParser

1
2
3
4
5
6
7
8
9
10
from langchain_core.output_parsers import CommaSeparatedListOutputParser

parser = CommaSeparatedListOutputParser()
prompt = prompt.partial(
format_instructions=parser.get_format_instructions()
)

chain = prompt | llm | parser
result = chain.invoke({"query": "列出3种编程语言"})
print(result) # ['Python', 'Java', 'JavaScript']

2. JsonOutputParser

1
2
3
4
5
6
7
8
9
10
11
12
13
from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel

class Person(BaseModel):
name: str
age: int
city: str

parser = JsonOutputParser(pydantic_object=Person)

chain = prompt | llm | parser
result = chain.invoke({"query": "张三,25岁,居住在北京"})
print(result) # {'name': '张三', 'age': 25, 'city': '北京'}

3. StrOutputParser(最常用)

1
2
3
4
from langchain_core.output_parsers import StrOutputParser

# 简单场景:只需要文本输出
chain = prompt | llm | StrOutputParser()

消息角色说明

角色说明
SystemMessage系统指令(全局行为定义)
HumanMessage用户输入(也称 User)
AIMessageAI 输出(包含 content + metadata)
ToolMessage工具调用结果(用于 Function Calling)
1
2
3
4
5
6
7
from langchain_core.messages import SystemMessage, HumanMessage

messages = [
SystemMessage(content="你是一个严谨的技术助手"),
HumanMessage(content="解释一下什么是 RAG"),
]
response = llm.invoke(messages)

完整示例:结构化输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel

class MovieReview(BaseModel):
title: str
rating: float
summary: str
genre: list[str]

parser = JsonOutputParser(pydantic_object=MovieReview)

prompt = ChatPromptTemplate.from_messages([
("system", "你是一个影评人,基于用户输入输出JSON"),
("human", "帮我分析电影:{movie}")
]).partial(
format_instructions=parser.get_format_instructions()
)

llm = ChatOpenAI(model="gpt-4o", temperature=0.3)
chain = prompt | llm | parser

result = chain.invoke({"movie": "流浪地球"})
# {'title': '流浪地球', 'rating': 8.5, 'summary': '...', 'genre': ['科幻', '灾难']}