ChatLLM 对话模型¶
ChatLLM 是专门为对话式场景设计的 LLM 抽象类,适合多轮对话、工具调用、知识问答等场景。主流模型如 GPT、Claude、Gemini 等都属于 ChatLLM 类型。
设计理念¶
为什么需要 ChatLLM¶
虽然 BaseLLM 提供了基础功能,但对话场景有特殊需求:
- 消息历史管理:需要维护多轮对话的历史记录
- Prompt 位置精确控制:系统消息、用户输入、中间结果需要插入不同位置
- 工具调用集成:需要将工具描述和工具调用结果正确地融入对话流
- 多模态对话:支持图片、视频等富媒体输入
- 输入格式化:有时需要重新格式化用户输入(如提取关键信息)
ChatLLM 在 BaseLLM 基础上,针对这些需求进行了专门设计。
与 GenerationLLM 的区别¶
| 特性 | ChatLLM | GenerationLLM |
|---|---|---|
| 主要用途 | 多轮对话、工具调用 | 连续文本生成 |
| 响应格式 | 支持结构化(JSON/工具调用) | 仅纯文本 |
| 典型场景 | QA、代码助手、数据分析 | DSL 生成、代码编辑 |
| 消息结构 | 支持多角色(user/assistant/system/tool) | 简化的输入输出 |
核心概念¶
Prompt 位置系统¶
ChatLLM 提供了 5 个精确的 Prompt 插入位置,用于构建复杂的对话上下文:
最终消息顺序:
┌──────────────────────────────────────┐
│ 1. system_msg_prompt │ ← 所有消息顶部
├──────────────────────────────────────┤
│ 2. conversation_msgs │ ← 历史对话
├──────────────────────────────────────┤
│ 3. before_input_msg_prompt │ ← 当前输入前
├──────────────────────────────────────┤
│ 4. input_msg (或 reformat 后的) │ ← 当前输入
├──────────────────────────────────────┤
│ 5. after_input_msg_prompt │ ← 当前输入后
├──────────────────────────────────────┤
│ 6. intermediate_msgs │ ← 工具调用中间结果
├──────────────────────────────────────┤
│ 7. after_intermediate_msg_prompt │ ← 中间消息后
└──────────────────────────────────────┘
各位置的使用场景¶
1. system_msg_prompt¶
用途:定义系统角色、全局规则、工具列表
from tfrobot.brain.chain.prompt.memo_prompt import MemoPrompt
from tfrobot.brain.chain.prompt.knowledge_prompt import KnowledgePrompt
llm.system_msg_prompt = [
MemoPrompt(template="你是一个专业的代码助手,擅长 Python 开发。"),
ToolPrompt(), # 自动生成工具描述
KnowledgePrompt(), # 自动注入知识库
]
2. before_input_msg_prompt¶
用途:提供任务背景、上下文说明
from tfrobot.brain.chain.prompt.memo_prompt import MemoPrompt
llm.before_input_msg_prompt = [
MemoPrompt(template="当前项目是一个 Web 框架,使用 FastAPI 开发。"),
]
3. after_input_msg_prompt¶
用途:约束输出格式、添加额外要求
from tfrobot.brain.chain.prompt.memo_prompt import MemoPrompt
llm.after_input_msg_prompt = [
MemoPrompt(template="请使用 Markdown 格式回复,代码块标明语言。"),
]
4. after_intermediate_msg_prompt¶
用途:引导工具调用后的下一步行动
from tfrobot.brain.chain.prompt.memo_prompt import MemoPrompt
llm.after_intermediate_msg_prompt = [
MemoPrompt(template="请根据工具返回结果,继续完成任务。"),
]
5. reformat_input_prompt¶
用途:转换、预处理用户输入
from tfrobot.brain.chain.prompt.reformat_prompt import ReformatPrompt
llm.reformat_input_prompt = [
ReformatPrompt(template="用户问题:{{ user_input.input }}"),
]
消息格式化流程¶
def format_to_request_msgs(
self,
current_input: BaseMessage,
prompt_ctx: PromptContext
) -> ReqeustMsgs:
处理流程:
PromptContext (工具、知识、文档等)
↓
┌─────────────────────────────────────┐
│ 1. 渲染 system_msg_prompt │ → LLMSystemMessage
├─────────────────────────────────────┤
│ 2. 处理 conversation_msgs │ → 转换为 LLM 格式
│ - 调用 to_llm_request(use_summary=True) │
│ - 支持摘要模式(减少 token) │
├─────────────────────────────────────┤
│ 3. 渲染 before_input_msg_prompt │ → LLMSystemMessage
├─────────────────────────────────────┤
│ 4. 处理 input_msg │ → LLMUserMessage
│ - 如果有 reformat_input_prompt │ → 使用 Prompt 生成的内容
│ - 否则使用 current_input.to_llm_request() │
├─────────────────────────────────────┤
│ 5. 渲染 after_input_msg_prompt │ → LLMSystemMessage
├─────────────────────────────────────┤
│ 6. 处理 intermediate_msgs │ → 转换为 LLM 格式
│ - 最后一条不使用摘要 │
│ - 其他使用摘要 │
├─────────────────────────────────────┤
│ 7. 渲染 after_intermediate_msg_prompt │ → LLMSystemMessage
└─────────────────────────────────────┘
↓
ReqeustMsgs (结构化消息容器)
↓
to_list() → list[BaseLLMMessage]
配置参数¶
核心参数¶
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
system_msg_prompt |
list[BasePrompt] |
系统消息提示列表 | [] |
before_input_msg_prompt |
list[BasePrompt] |
用户输入前提示列表 | [] |
after_input_msg_prompt |
list[BasePrompt] |
用户输入后提示列表 | [] |
after_intermediate_msg_prompt |
list[BasePrompt] |
中间消息后提示列表 | [] |
reformat_input_prompt |
list[BasePrompt] |
重新格式化输入提示列表 | [] |
工具提示配置¶
from tfrobot.brain.chain.prompt.tool_prompt import ToolPrompt
# 原生模式(支持 Function Calling 的模型)
llm.system_msg_prompt.append(
ToolPrompt() # 自动生成 OpenAI 格式工具描述
)
# DSL 模式(不支持工具调用的模型)
from tfrobot.brain.chain.prompt.dsl_prompt import DSLToolPrompt
llm.system_msg_prompt.append(
DSLToolPrompt() # 生成 DSL 语法描述
)
知识库配置¶
from tfrobot.brain.chain.prompt.knowledge_prompt import KnowledgePrompt
llm.system_msg_prompt.append(
KnowledgePrompt(
template="相关资料:\n{{ knowledge.knowledge }}"
)
)
使用示例¶
基础对话¶
from tfrobot.brain.chain.llms import GPT
from tfrobot.schema.message.conversation.message_dto import TextMessage
from tfrobot.schema.users import BaseUser
# 创建模型
llm = GPT(name="gpt-4o")
# 构建用户输入
user_input = TextMessage(
role="user",
creator=BaseUser(name="User", uid="1"),
content="你好,请介绍一下 TFRobot 项目。"
)
# 调用模型
result = llm.complete(current_input=user_input)
print(result.generations[0].text)
配置系统角色¶
from tfrobot.brain.chain.llms import Claude
from tfrobot.brain.chain.prompt.memo_prompt import MemoPrompt
from tfrobot.brain.chain.prompt.template.jinja2_template import Jinja2PromptTemplate
from tfrobot.schema.types import Locale
llm = Claude(name="claude-3-5-sonnet-20241022")
# 配置系统角色
llm.system_msg_prompt = [
MemoPrompt(
template=Jinja2PromptTemplate(
templates={
Locale.ZH: "你是一个专业的 Python 开发助手,擅长代码调试和性能优化。",
Locale.EN: "You are a professional Python developer assistant, skilled in code debugging and performance optimization."
}
)
)
]
result = llm.complete(current_input=user_input)
工具调用¶
from tfrobot.brain.chain.llms import GPT
from tfrobot.brain.chain.prompt.tool_prompt import ToolPrompt
from tfrobot.drive.tool.tool import tool
@tool
def calculate(expression: str) -> str:
"""计算数学表达式"""
try:
return str(eval(expression))
except Exception as e:
return f"Error: {str(e)}"
llm = GPT(name="gpt-4o")
llm.system_msg_prompt = [ToolPrompt()]
result = llm.complete(
current_input=TextMessage(content="计算 123 * 456 的结果"),
tools=[calculate]
)
多轮对话¶
from tfrobot.brain.chain.llms import Claude
from tfrobot.schema.message.conversation.message_dto import TextMessage
llm = Claude(name="claude-3-5-sonnet-20241022")
# 第一轮对话
msg1 = TextMessage(content="什么是 FastAPI?")
result1 = llm.complete(current_input=msg1)
print(result1.generations[0].text)
# 第二轮对话(带上历史)
conversation = [msg1, result1.generations[0].to_message()]
msg2 = TextMessage(content="它和 Flask 有什么区别?")
result2 = llm.complete(
current_input=msg2,
conversation=conversation
)
print(result2.generations[0].text)
添加知识库¶
from tfrobot.brain.chain.llms import GPT
from tfrobot.brain.chain.prompt.knowledge_prompt import KnowledgePrompt
llm = GPT(name="gpt-4o")
knowledge = """
TFRobot 是一个基于 Python 的 LLM 智能体平台。
核心特性:思维链推理、三层记忆、工具执行。
架构设计:模拟人类生理结构(大脑、驱动、神经)。
"""
result = llm.complete(
current_input=TextMessage(content="TFRobot 的核心特性是什么?"),
knowledge=knowledge
)
多模态输入¶
from tfrobot.brain.chain.llms import GPT
from tfrobot.schema.message.conversation.message_dto import MultiPartMessage, ImageMessage, TextMessage
from tfrobot.schema.types import Locale
llm = GPT(name="gpt-4o")
# 构建多模态消息
msg = MultiPartMessage(
content=[
TextPart(text="这张图片是什么?"),
ImagePart(image_url=ImgUrl(url="path/to/image.jpg"))
],
creator=BaseUser(name="User", uid="1")
)
result = llm.complete(current_input=msg)
高级用法¶
自定义 Prompt 位置¶
from tfrobot.brain.chain.prompt.base import BasePrompt
from tfrobot.schema.meta.tf_field import TFField
class CustomPrompt(BasePrompt):
template = TFField(
default_factory=lambda: Jinja2PromptTemplate(
templates={Locale.ZH: "自定义内容: {{ variable }}"}
)
)
# 插入到不同位置
llm.before_input_msg_prompt.append(CustomPrompt())
llm.after_input_msg_prompt.append(CustomPrompt())
使用 Intermediate Messages¶
from tfrobot.schema.message.conversation.message_dto import AssistantTextMessage
# 模拟工具调用的中间消息
intermediate_msgs = [
AssistantTextMessage(
content="我已经调用了搜索工具,找到了相关资料。"
),
ToolReturnMessage(
tool_reses=[...],
content="搜索结果:..."
)
]
result = llm.complete(
current_input=user_input,
intermediate_msgs=intermediate_msgs
)
动态 Prompt¶
from tfrobot.brain.chain.prompt.memo_prompt import MemoPrompt
# 根据条件添加 Prompt
if need_tool_prompt:
llm.system_msg_prompt.append(ToolPrompt())
if need_knowledge:
llm.system_msg_prompt.append(KnowledgePrompt())
最佳实践¶
1. Prompt 组织建议¶
# 推荐的组织方式
llm.system_msg_prompt = [
MemoPrompt(...), # 1. 系统角色
ToolPrompt(), # 2. 工具列表
KnowledgePrompt(), # 3. 知识库
]
llm.before_input_msg_prompt = [
MemoPrompt(...), # 任务背景
]
llm.after_input_msg_prompt = [
MemoPrompt(...), # 输出格式要求
]
llm.after_intermediate_msg_prompt = [
MemoPrompt(...), # 工具调用后的引导
]
2. Token 优化¶
# 使用摘要模式减少历史消息的 token 消耗
result = llm.complete(
current_input=user_input,
conversation=conversation # 内部自动使用摘要模式
)
# 控制知识库大小
if len(knowledge) > 1000:
knowledge = knowledge[:1000] # 截断过长内容
3. 错误处理¶
from tfrobot.schema.exceptions import ContextTooLargeError
try:
result = llm.complete(
current_input=user_input,
conversation=long_conversation
)
except ContextTooLargeError as e:
# 手动压缩上下文
compacted_conv, _, _, _, _ = llm.collapse_context(
current_input=user_input,
conversation=conversation,
to_size=e.target_size
)
result = llm.complete(
current_input=user_input,
conversation=compacted_conv
)
4. 多语言支持¶
from tfrobot.schema.types import Locale
# 设置 LLM 内部语言
llm = GPT(name="gpt-4o", locale=Locale.ZH)
# 多语言 Prompt
llm.system_msg_prompt = [
MemoPrompt(
template=Jinja2PromptTemplate(
templates={
Locale.ZH: "你是一个中文助手。",
Locale.EN: "You are an English assistant."
}
)
)
]
与其他模块的协作¶
与 Chain 模块¶
from tfrobot.brain.chain import SingleChain
chain = SingleChain(llm=llm)
result = chain.run(input_message=user_input)
# Chain 会自动管理 conversation、intermediate_msgs 等
与 Memory 模块¶
from tfrobot.brain.memory import BufferStore
# 从 Memory 加载历史
buffer_store = BufferStore()
conversation = buffer_store.get_recent_messages(limit=10)
result = llm.complete(
current_input=user_input,
conversation=conversation
)
# 保存到 Memory
buffer_store.add_message(user_input)
buffer_store.add_message(result.generations[0].to_message())