Skip to content

ChatLLM 对话模型

ChatLLM 是专门为对话式场景设计的 LLM 抽象类,适合多轮对话、工具调用、知识问答等场景。主流模型如 GPT、Claude、Gemini 等都属于 ChatLLM 类型。

设计理念

为什么需要 ChatLLM

虽然 BaseLLM 提供了基础功能,但对话场景有特殊需求:

  1. 消息历史管理:需要维护多轮对话的历史记录
  2. Prompt 位置精确控制:系统消息、用户输入、中间结果需要插入不同位置
  3. 工具调用集成:需要将工具描述和工具调用结果正确地融入对话流
  4. 多模态对话:支持图片、视频等富媒体输入
  5. 输入格式化:有时需要重新格式化用户输入(如提取关键信息)

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())

相关文档