Skip to content

GenerationLLM 生成模型

GenerationLLM 是为连续文本生成场景设计的 LLM 抽象类,适合 DSL 生成、代码编辑、图提取等需要连续输出的场景。DeskLLM 是 GenerationLLM 的主要实现,专注于桌面环境模拟。

设计理念

为什么需要 GenerationLLM

虽然 ChatLLM 已经可以处理大部分场景,但在某些特殊需求下,生成模型更有优势:

  1. 连续工具调用:生成模型在连续工具调用时效果更好
  2. 不需要数据结构:只需要不断追加内容,无需考虑复杂的 JSON 结构
  3. 流式输出:生成模型的输出可以自然地逐步生成
  4. 专用场景优化:如 DSL 生成、代码编辑、图提取等
  5. 简化 Prompt 结构:通过单一 Prompt 控制整个生成过程

与 ChatLLM 的区别

特性 ChatLLM GenerationLLM
主要用途 多轮对话、工具调用 连续文本生成
响应格式 支持结构化(JSON/工具调用) 仅纯文本
API 类型 Chat Completions API Completions API
消息结构 支持多角色(user/assistant/system/tool) 简化的输入输出
典型场景 QA、代码助手、数据分析 DSL 生成、代码编辑、图提取
Prompt 系统 5 个 Prompt 位置 7 个 Prompt 位置

DeskLLM 桌面环境模拟

DeskLLM 是 GenerationLLM 的主要实现,专门用于模拟桌面环境的智能体。

核心概念

DeskLLM 将 LLM 视为一个拥有自己桌面环境的智能体,它可以在这个环境中执行各种任务,如编辑文件、运行代码等。

核心优势: - 统一的接口设计:便于切换不同的底层大语言模型 - 丰富的提示词管理:支持多种提示词模板和 7 层架构 - 灵活的上下文管理:包括系统消息、指令消息、工作环境状态等 - 工具调用支持:集成工具执行和中间结果处理

桌面环境隐喻

┌─────────────────────────────────────────┐
│         DeskLLM 桌面环境                 │
│                                          │
│  ┌──────────────┐  ┌──────────────┐     │
│  │  Editor      │  │  Terminal    │     │
│  │  (代码编辑器) │  │  (命令行)    │     │
│  └──────────────┘  └──────────────┘     │
│                                          │
│  状态变化:                                │
│  original_desk → 操作 → current_desk     │
└─────────────────────────────────────────┘

Prompt 结构(7 层架构)

DeskLLM 使用与 ChatLLM 不同的 Prompt 结构,专门优化了桌面环境模拟场景:

Prompt 类型 说明 典型用途
system_prompt 系统角色、工具范围、背景信息 限定 LLM 角色,提供全局上下文
instruction_prompt Few-shot 学习示例 展示期望的行事风格和规则
original_desk_screenshot_prompt 任务初始时的环境状态 记录未编辑时的文件原始内容
purpose_prompt 任务目标和要求 用户输入或当前任务描述
intermediate_prompt 中间结果和状态变更 记录已执行的操作和状态变化
current_desk_screenshot_prompt 任务进行时的环境状态 当前文件内容(随操作变化)
prefix_prompt 输出前缀 强制 LLM 以特定格式开头

Prompt 渲染顺序

system_prompt          ← 全局角色定义
    ↓
instruction_prompt    ← Few-shot 示例
    ↓
original_desk_screenshot_prompt  ← 初始状态
    ↓
purpose_prompt         ← 当前任务
    ↓
intermediate_prompt    ← 中间步骤
    ↓
current_desk_screenshot_prompt  ← 当前状态
    ↓
prefix_prompt          ← 输出引导
    ↓
[LLM 生成内容]

使用场景

  • DSL 生成:生成特定领域语言的代码(如 SQL、GraphQL、Excel 公式)
  • 代码编辑:自动编辑代码文件(增量修改而非重写)
  • 图提取:从文本中提取图谱结构(RDF、OWL)
  • 桌面自动化:控制桌面应用程序(模拟鼠标键盘操作)

快速开始

使用 DeskLLM

from tfrobot.brain.chain.llms.generation_llms.desk_llm.openai_desk import GPTDesk
from tfrobot.brain.chain.prompt.memo_prompt import MemoPrompt
from tfrobot.schema.message.conversation.message_dto import TextMessage

# 创建 DeskLLM
desk_llm = GPTDesk(name="gpt-4o")

# 配置系统提示
desk_llm.system_prompt = [
    MemoPrompt(template="你是一个代码编辑助手,专注于 Python 开发。")
]

# 调用
result = desk_llm.complete(
    current_input=TextMessage(content="帮我写一个快速排序函数")
)
print(result.generations[0].text)

代码编辑场景示例

from tfrobot.brain.chain.llms.generation_llms.desk_llm.claude_desk import ClaudeDesk
from tfrobot.brain.chain.prompt.memo_prompt import MemoPrompt

desk_llm = ClaudeDesk(name="claude-3-5-sonnet-20241022")

# 配置代码编辑场景的 Prompts
desk_llm.system_prompt = [
    MemoPrompt(template="你是一个 Python 代码编辑助手。")
]

# 原始文件内容
original_code = """
def add(a, b):
    return a + b
"""

desk_llm.original_desk_screenshot_prompt = [
    MemoPrompt(template=f"原始文件内容:\n```python\n{original_code}\n```")
]

# 当前任务
desk_llm.purpose_prompt = [
    MemoPrompt(
        template="请为 add 函数添加类型注解和文档字符串。"
    )
]

# 强制输出格式
desk_llm.prefix_prompt = [
    MemoPrompt(template="修改后的代码:\n```python\n")
]

# 生成
result = desk_llm.complete(current_input=TextMessage(content="开始编辑"))
print(result.generations[0].text)

DSL 生成场景示例

from tfrobot.brain.chain.llms.generation_llms.desk_llm.gemini_desk import GeminiDesk

desk_llm = GeminiDesk(name="gemini-2.5-flash")

# 配置 DSL 生成场景
desk_llm.system_prompt = [
    MemoPrompt(template="你是一个 SQL 专家,擅长根据自然语言描述生成 SQL 查询。")
]

# Few-shot 示例
desk_llm.instruction_prompt = [
    MemoPrompt(template="""
示例 1:
输入:查询所有年龄大于 18 的用户
输出:SELECT * FROM users WHERE age > 18;

示例 2:
查询每个部门的平均工资
输出:SELECT department, AVG(salary) FROM employees GROUP BY department;
""")
]

# 当前任务
desk_llm.purpose_prompt = [
    MemoPrompt(template="输入:查询销售额排名前 10 的产品")
]

# 强制输出前缀
desk_llm.prefix_prompt = [
    MemoPrompt(template="输出:")
]

result = desk_llm.complete(current_input=TextMessage(content="生成 SQL"))
print(result.generations[0].text)

核心参数

通用参数

参数 类型 默认值 说明
name str - 模型名称(如 gpt-4o, claude-3-5-sonnet-20241022
temperature float 1.0 采样温度,0-2 之间
max_tokens int 4096 最大生成 tokens 数
top_p float 1.0 核采样参数
stop str\|list[str] - 停止词列表
stream bool False 是否流式输出

Prompt 参数

参数 类型 默认值 说明
system_prompt list[BasePrompt] [] 系统提示(角色定义)
instruction_prompt list[BasePrompt] [] 指令提示(Few-shot 示例)
original_desk_screenshot_prompt list[BasePrompt] [] 初始环境状态
purpose_prompt list[BasePrompt] [UserInputPrompt(...)] 任务目的提示
intermediate_prompt list[BasePrompt] [] 中间结果提示
current_desk_screenshot_prompt list[BasePrompt] [] 当前环境状态
prefix_prompt list[BasePrompt] [] 输出前缀提示

提供商特定参数

不同提供商有额外的配置参数,详见各提供商文档。

支持的实现

类名 提供商 说明 默认模型
GPTDesk OpenAI GPT 系列模型 gpt-4-turbo-preview
ClaudeDesk Anthropic Claude 系列模型 claude-3-opus-20240229
GeminiDesk Google Gemini 系列模型 gemini-2.5-flash
DeepSeekDesk DeepSeek DeepSeek 系列模型 deepseek-coder
OllamaDesk Ollama 本地模型 codellama:7b
SGLangDesk SGLang SGLang 本地服务 -
TencentDSDesk 腾讯 腾讯混元系列 -

重要约束

仅支持纯文本返回

DeskLLM 不支持结构化响应格式(JSON/JSON Schema),只能返回纯文本:

# ❌ 错误:不支持 JSON 格式
desk_llm = GPTDesk(
    name="gpt-4o",
    response_format={"type": "json_object"}  # 会抛出 ValueError
)

# ✅ 正确:使用纯文本,自行解析
desk_llm = GPTDesk(name="gpt-4o")
# 在 Prompt 中提示模型返回 JSON
desk_llm.system_prompt = [
    MemoPrompt(template="请以 JSON 格式返回结果。")
]

result = desk_llm.complete(...)
# 手动解析 result.generations[0].text
import json
json_data = json.loads(result.generations[0].text)

代理配置

部分 DeskLLM 实现支持代理配置:

# OpenAI/Claude/Gemini 支持 HTTP(S) 代理
desk_llm = GPTDesk(
    name="gpt-4o",
    proxy_host="127.0.0.1",
    proxy_port=7890,
    proxy_user=None,  # 可选
    proxy_pass=None,  # 可选
)

# Gemini 还支持 SOCKS5 代理
from tfrobot.brain.chain.llms.generation_llms.desk_llm.gemini_desk import GeminiDesk

desk_llm = GeminiDesk(
    name="gemini-2.5-flash",
    socks5_proxy=True,  # 使用 SOCKS5
    proxy_host="127.0.0.1",
    proxy_port=1080,
)

API 映射

DeskLLM 使用各提供商的 Completions API 而非 Chat Completions API:

提供商 API 类型 端点
OpenAI Completions POST /v1/completions
Anthropic Completions POST /v1/messages (legacy)
Gemini Generate Content POST /v1beta/models/{model}:generateContent

最佳实践

1. Prompt 顺序设计

合理设计 Prompt 的顺序和内容:

desk_llm = GPTDesk(name="gpt-4o")

# 1. 定义全局角色
desk_llm.system_prompt = [
    MemoPrompt(template="你是一个专业的 Python 开发者。")
]

# 2. 提供示例
desk_llm.instruction_prompt = [
    MemoPrompt(template="""
示例:
输入:创建一个Person类
输出:
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
""")
]

# 3. 提供初始状态
desk_llm.original_desk_screenshot_prompt = [
    MemoPrompt(template="# 当前文件为空\n")
]

# 4. 定义任务
desk_llm.purpose_prompt = [
    MemoPrompt(template="请创建一个Student类,继承Person类。")
]

# 5. 提供中间步骤(如果有)
desk_llm.intermediate_prompt = []

# 6. 提供当前状态
desk_llm.current_desk_screenshot_prompt = []

# 7. 强制输出格式
desk_llm.prefix_prompt = [
    MemoPrompt(template="```python\n")
]

2. 状态管理

在多轮生成中正确管理环境状态:

# 初始状态
original_content = read_file("main.py")

desk_llm.original_desk_screenshot_prompt = [
    MemoPrompt(template=f"原始文件内容:\n{original_content}")
]

# 第一次修改
desk_llm.purpose_prompt = [
    MemoPrompt(template="添加错误处理")
]
result1 = desk_llm.complete(...)
current_content = result1.generations[0].text

# 第二次修改(基于第一次的结果)
desk_llm.current_desk_screenshot_prompt = [
    MemoPrompt(template=f"当前文件内容:\n{current_content}")
]
desk_llm.intermediate_prompt = [
    MemoPrompt(template="已添加错误处理。")
]
desk_llm.purpose_prompt = [
    MemoPrompt(template="添加类型注解")
]
result2 = desk_llm.complete(...)

3. 多模态支持

部分 DeskLLM 实现支持多模态输入:

from tfrobot.brain.chain.llms.generation_llms.desk_llm.gemini_desk import GeminiDesk
from tfrobot.schema.message.conversation.message_dto import MultiPartMessage
from tfrobot.schema.message.msg_part import TextPart, ImagePart

desk_llm = GeminiDesk(name="gemini-2.5-flash")

# 多模态输入
msg = MultiPartMessage(content=[
    TextPart(text="请描述这个界面的布局"),
    ImagePart(image_url=ImgUrl(url="screenshot.png")),
])

result = desk_llm.complete(current_input=msg)

错误处理

上下文超长

当上下文超出限制时,抛出 ContextTooLargeError

from tfrobot.schema.exceptions import ContextTooLargeError

try:
    result = desk_llm.complete(current_input=long_input)
except ContextTooLargeError as e:
    print(f"当前大小: {e.current_size}")
    print(f"目标大小: {e.target_size}")
    print(f"模型: {e.model_name}")
    # 由 Chain 层自动处理压缩

参数验证

# ❌ 错误:尝试设置 JSON 格式
try:
    desk_llm = GPTDesk(
        name="gpt-4o",
        response_format={"type": "json_object"}
    )
except ValueError as e:
    print(e)  # "DeskLLM仅支持纯文本返回..."

性能优化

1. 使用流式输出

desk_llm = GPTDesk(name="gpt-4o", stream=True)

result = desk_llm.complete(current_input=user_input)
# 内容会逐步生成

2. 控制 max_tokens

# 对于简单任务,限制输出长度
desk_llm = GPTDesk(
    name="gpt-4o",
    max_tokens=512  # 减少延迟和成本
)

3. 使用合适的模型

# 简单任务使用小模型
desk_llm = GPTDesk(name="gpt-4o-mini")

# 复杂任务使用大模型
desk_llm = GPTDesk(name="gpt-4o")

架构设计

类继承结构

DeskLLM 采用了抽象基类 + 具体实现的设计模式:

GenerationLLM (抽象基类)
    └── DeskLLM (抽象基类)
        ├── GPTDesk (OpenAI 实现)
        ├── GPTGenDesk (OpenAI Completions API)
        ├── ClaudeDesk (Anthropic 实现)
        ├── GeminiDesk (Google 实现)
        ├── DeepSeekDesk (DeepSeek 实现)
        ├── OllamaDesk (Ollama 本地实现)
        ├── SGLangDesk (SGLang 本地实现)
        └── TencentDSDesk (腾讯混元实现)

每个具体实现类负责与特定的 LLM 服务提供商 API 进行交互,而共享相同的接口和基础功能。

请求处理流程

DeskLLM 的标准请求处理流程:

1. 构造请求参数 (construct_request_params)
   ├─ 收集 7 层 Prompt 内容
   ├─ 构造消息列表
   └─ 设置参数(temperature, max_tokens, etc.)

2. 发送请求到 LLM API (complete/async_complete)
   ├─ 调用提供商 API
   ├─ 处理流式/非流式响应
   └─ 错误处理和重试

3. 处理响应并构造结果 (construct_llm_result)
   ├─ 提取生成文本
   ├─ 统计 token 使用量
   └─ 返回 LLMResult 对象

模板系统

DeskLLM 支持多种提示词模板系统:

模板类型 推荐度 特点
Jinja2PromptTemplate ✅ 推荐 支持条件语句、循环、宏定义、多语言
FStrPromptTemplate ⚠️ 备选 简单格式化,功能有限
StringTemplate ⚠️ 备选 静态字符串

推荐使用 Jinja2PromptTemplate:

from tfrobot.brain.chain.prompt.template.jinja2_template import Jinja2PromptTemplate
from tfrobot.schema.types import Locale

template = Jinja2PromptTemplate(
    templates={
        Locale.EN: "You are a {{ role }}. Your task is to {{ task }}.",
        Locale.ZH: "你是一个{{ role }}。你的任务是{{ task }}。"
    }
)

实现原则

基本原则

  1. 接口一致性:所有 DeskLLM 实现类应保持相同的接口,便于切换不同的底层模型
  2. 错误处理:实现应包含完善的错误处理机制,特别是网络错误和 API 限制错误
  3. 上下文管理:合理管理上下文长度,避免超出模型的最大上下文窗口
  4. 参数验证:使用 Pydantic 进行参数验证,确保参数的正确性
  5. 异步支持:同时提供同步和异步接口,满足不同场景的需求

注意事项

注意事项 说明
仅支持纯文本 DeskLLM 不支持 JSON Schema 格式,只能返回纯文本
上下文窗口管理 当上下文超出限制时,应有策略进行上下文压缩
代理配置 在网络受限环境中,需要正确配置代理
API 密钥管理 安全存储和使用 API 密钥,优先使用环境变量
重试机制 对于可重试的错误(如网络超时),应实现适当的重试策略

扩展 DeskLLM

创建新的 DeskLLM 实现

要为新的 LLM 服务提供商创建 DeskLLM 实现,需要:

1. 继承 DeskLLM 抽象基类

from tfrobot.brain.chain.llms.generation_llms.desk_llm.base import DeskLLM

class NewProviderDesk(DeskLLM):
    """新提供商的 DeskLLM 实现"""
    pass

2. 实现必要的方法: - model_post_init:初始化客户端 - construct_request_params:构造请求参数 - complete:同步请求处理 - async_complete:异步请求处理 - construct_llm_result:构造结果对象

3. 参考现有实现: - OpenAI: openai_desk.py, openai_gen_desk.py - Anthropic: claude_desk.py - Google: gemini_desk.py - DeepSeek: deepseek_desk.py

自定义提示词模板

可以通过继承 BasePrompt 和使用 Jinja2PromptTemplate 创建自定义提示词模板:

from tfrobot.brain.chain.prompt.base import BasePrompt
from tfrobot.brain.chain.prompt.template.jinja2_template import Jinja2PromptTemplate
from tfrobot.schema.meta.tf_field import TFField
from tfrobot.schema.types import Locale

class CustomPrompt(BasePrompt):
    """自定义提示词模板"""
    template = TFField(
        default_factory=lambda: Jinja2PromptTemplate(
            templates={
                Locale.EN: "Custom template: {{ variable }}",
                Locale.ZH: "自定义模板: {{ variable }}"
            }
        )
    )

故障排除

常见问题

问题 症状 解决方案
上下文长度超限 API 返回 "context_length_exceeded" 错误 减少提示词长度,或使用 collapse_context 方法压缩上下文
API 认证失败 API 返回 401 错误 检查 API 密钥是否正确,是否过期
网络超时 请求超时错误 增加 timeout 参数,或配置代理
参数错误 创建时抛出 ValueError 检查是否设置了不支持的参数(如 response_format

调试技巧

  1. 查看实际发送的 Prompt

    result = desk_llm.complete(current_input=user_input)
    print(result.meta_info.get("prompt", ""))
    

  2. 检查 Token 使用量

    print(f"输入: {result.llm_output.tokens_input}")
    print(f"输出: {result.llm_output.tokens_output}")
    

  3. 启用详细日志

    import logging
    logging.basicConfig(level=logging.DEBUG)
    

  4. 使用异常处理获取详细信息

    from tfrobot.schema.exceptions import ContextTooLargeError
    
    try:
        result = desk_llm.complete(current_input=long_input)
    except ContextTooLargeError as e:
        print(f"当前大小: {e.current_size}")
        print(f"目标大小: {e.target_size}")
        print(f"模型: {e.model_name}")
    

最佳实践总结

模型选择

根据任务复杂度和性能要求选择合适的模型:

任务类型 推荐模型 理由
简单任务 GPT-4o-mini, Gemini 2.0 Flash 成本低、速度快
复杂推理 GPT-4o, Claude Opus, DeepSeek-Reasoner 推理能力强
中文场景 DeepSeek-Chat, GLM-4.7 中文优化
代码生成 GPT-4o, Claude Opus, GLM-4.7 代码能力强
多模态 GPT-4o, Gemini 3 Pro 多模态支持完善

提示词设计

  1. 使用 Jinja2 模板:优先使用 Jinja2PromptTemplate
  2. 分层提示词:合理利用 7 层 Prompt,清晰分离不同类型的信息
  3. 保持简洁:避免冗余信息,减少 token 消耗
  4. 结构化信息:对于复杂信息,使用结构化格式(如表格、代码块)
  5. Few-shot 学习:在 instruction_prompt 中提供示例

状态管理

  1. 初始状态:使用 original_desk_screenshot_prompt 记录
  2. 中间步骤:使用 intermediate_prompt 记录已执行的操作
  3. 当前状态:使用 current_desk_screenshot_prompt 记录当前状态
  4. 状态同步:确保 Prompt 中的状态与实际文件内容一致

相关文档

基础文档

DeskLLM 实现文档

云端 API 实现(推荐用于生产环境)

  • GeminiDesk - Google Gemini 实现
  • 多模态任务首选 - 1M 上下文,完善的多模态支持
  • ✅ 国内访问相对稳定
  • ✅ SOCKS5 代理支持

  • DeepSeekDesk - DeepSeek 实现

  • 纯文本任务推荐 - 中文能力强,价格低
  • ✅ FIM(Fill-in-the-Middle)支持
  • ✅ 测试充分,稳定性好

  • TencentDSDesk - 腾讯混元实现

  • ✅ 国内访问稳定
  • ✅ 功能完善,流式输出支持

  • GPTDesk - OpenAI Responses API 实现

  • ⚠️ Completion API 支持有限
  • ⚠️ 国内访问困难

  • GPTGenDesk - OpenAI Completions API 实现

  • ✅ 支持停止词(最多 4 个)
  • ⚠️ 仅支持 gpt-3.5-turbo-instruct 模型

  • ClaudeDesk - Anthropic Claude 实现

  • ⚠️ 国内访问困难
  • ⚠️ 未经过充分测试
  • 💡 建议使用 GeminiDesk 或 DeepSeekDesk 替代

本地模型实现(仅用于测试)

  • OllamaDesk - Ollama 本地模型实现
  • ⚠️ 仅适用于本地测试,不建议用于生产环境
  • ⚠️ 错误处理、测试覆盖均有不足
  • 💡 生产环境推荐使用云端 API

  • SGLangDesk - SGLang 本地服务实现

  • ⚠️ 仅适用于本地测试
  • ⚠️ 需要手动部署和维护