convex-agent
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseConvex Agent Component
Convex Agent 组件
Build AI agents with persistent message history, tool calling, real-time streaming, and durable workflows.
构建具备持久消息历史、工具调用、实时流式输出和可靠工作流的AI Agent。
Installation
安装
bash
npm install @convex-dev/agenttypescript
// convex/convex.config.ts
import { defineApp } from 'convex/server';
import agent from '@convex-dev/agent/convex.config';
const app = defineApp();
app.use(agent);
export default app;Run to generate component code before defining agents.
npx convex devbash
npm install @convex-dev/agenttypescript
// convex/convex.config.ts
import { defineApp } from 'convex/server';
import agent from '@convex-dev/agent/convex.config';
const app = defineApp();
app.use(agent);
export default app;在定义Agent之前,运行生成组件代码。
npx convex devCore Concepts
核心概念
Agent Definition
Agent 定义
typescript
// convex/agents.ts
import { Agent } from '@convex-dev/agent';
import { openai } from '@ai-sdk/openai';
import { components } from './_generated/api';
const supportAgent = new Agent(components.agent, {
name: 'Support Agent',
languageModel: openai.chat('gpt-4o-mini'),
textEmbeddingModel: openai.embedding('text-embedding-3-small'), // For vector search
instructions: 'You are a helpful support assistant.',
tools: { lookupAccount, createTicket },
stopWhen: stepCountIs(10) // Or use maxSteps: 10
});typescript
// convex/agents.ts
import { Agent } from '@convex-dev/agent';
import { openai } from '@ai-sdk/openai';
import { components } from './_generated/api';
const supportAgent = new Agent(components.agent, {
name: 'Support Agent',
languageModel: openai.chat('gpt-4o-mini'),
textEmbeddingModel: openai.embedding('text-embedding-3-small'), // For vector search
instructions: 'You are a helpful support assistant.',
tools: { lookupAccount, createTicket },
stopWhen: stepCountIs(10) // Or use maxSteps: 10
});Basic Usage (Two Approaches)
基础用法(两种方式)
Approach 1: Direct generation (simpler)
typescript
import { createThread } from '@convex-dev/agent';
export const chat = action({
args: { prompt: v.string() },
handler: async (ctx, { prompt }) => {
const threadId = await createThread(ctx, components.agent);
const result = await agent.generateText(ctx, { threadId }, { prompt });
return result.text;
}
});Approach 2: Thread object (more features)
typescript
export const chat = action({
args: { prompt: v.string() },
handler: async (ctx, { prompt }) => {
const { threadId, thread } = await agent.createThread(ctx);
const result = await thread.generateText({ prompt });
return { threadId, text: result.text };
}
});方式1:直接生成(更简单)
typescript
import { createThread } from '@convex-dev/agent';
export const chat = action({
args: { prompt: v.string() },
handler: async (ctx, { prompt }) => {
const threadId = await createThread(ctx, components.agent);
const result = await agent.generateText(ctx, { threadId }, { prompt });
return result.text;
}
});方式2:线程对象(功能更丰富)
typescript
export const chat = action({
args: { prompt: v.string() },
handler: async (ctx, { prompt }) => {
const { threadId, thread } = await agent.createThread(ctx);
const result = await thread.generateText({ prompt });
return { threadId, text: result.text };
}
});Continue Existing Thread
继续现有对话线程
typescript
export const continueChat = action({
args: { threadId: v.string(), prompt: v.string() },
handler: async (ctx, { threadId, prompt }) => {
// Message history included automatically
const result = await agent.generateText(ctx, { threadId }, { prompt });
return result.text;
}
});typescript
export const continueChat = action({
args: { threadId: v.string(), prompt: v.string() },
handler: async (ctx, { threadId, prompt }) => {
// 消息历史会自动包含在内
const result = await agent.generateText(ctx, { threadId }, { prompt });
return result.text;
}
});Asynchronous Pattern (Recommended)
异步模式(推荐)
Best practice: save message in mutation, generate response asynchronously.
typescript
import { saveMessage } from '@convex-dev/agent';
// Step 1: Mutation saves message and schedules generation
export const sendMessage = mutation({
args: { threadId: v.string(), prompt: v.string() },
handler: async (ctx, { threadId, prompt }) => {
const { messageId } = await saveMessage(ctx, components.agent, {
threadId,
prompt
});
await ctx.scheduler.runAfter(0, internal.chat.generateResponse, {
threadId,
promptMessageId: messageId
});
return messageId;
}
});
// Step 2: Action generates response
export const generateResponse = internalAction({
args: { threadId: v.string(), promptMessageId: v.string() },
handler: async (ctx, { threadId, promptMessageId }) => {
await agent.generateText(ctx, { threadId }, { promptMessageId });
}
});
// Shorthand for Step 2:
export const generateResponse = agent.asTextAction();最佳实践:在mutation中保存消息,异步生成响应。
typescript
import { saveMessage } from '@convex-dev/agent';
// 步骤1:Mutation保存消息并调度生成任务
export const sendMessage = mutation({
args: { threadId: v.string(), prompt: v.string() },
handler: async (ctx, { threadId, prompt }) => {
const { messageId } = await saveMessage(ctx, components.agent, {
threadId,
prompt
});
await ctx.scheduler.runAfter(0, internal.chat.generateResponse, {
threadId,
promptMessageId: messageId
});
return messageId;
}
});
// 步骤2:Action生成响应
export const generateResponse = internalAction({
args: { threadId: v.string(), promptMessageId: v.string() },
handler: async (ctx, { threadId, promptMessageId }) => {
await agent.generateText(ctx, { threadId }, { promptMessageId });
}
});
// 步骤2的简写形式:
export const generateResponse = agent.asTextAction();Generation Methods
生成方法
typescript
// Text generation
const result = await agent.generateText(ctx, { threadId }, { prompt });
// Structured output
const result = await agent.generateObject(
ctx,
{ threadId },
{
prompt: 'Extract user info',
schema: z.object({ name: z.string(), email: z.string() })
}
);
// Stream text (see STREAMING.md)
const result = await agent.streamText(ctx, { threadId }, { prompt });
// Multiple messages
const result = await agent.generateText(
ctx,
{ threadId },
{
messages: [
{ role: 'user', content: 'Context message' },
{ role: 'user', content: 'Actual question' }
]
}
);typescript
// 文本生成
const result = await agent.generateText(ctx, { threadId }, { prompt });
// 结构化输出
const result = await agent.generateObject(
ctx,
{ threadId },
{
prompt: 'Extract user info',
schema: z.object({ name: z.string(), email: z.string() })
}
);
// 流式文本输出(参见STREAMING.md)
const result = await agent.streamText(ctx, { threadId }, { prompt });
// 多条消息
const result = await agent.generateText(
ctx,
{ threadId },
{
messages: [
{ role: 'user', content: 'Context message' },
{ role: 'user', content: 'Actual question' }
]
}
);Querying Messages
查询消息
typescript
import { listUIMessages, paginationOptsValidator } from '@convex-dev/agent';
export const listMessages = query({
args: { threadId: v.string(), paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
return await listUIMessages(ctx, components.agent, args);
}
});React Hook:
typescript
import { useUIMessages } from '@convex-dev/agent/react';
const { results, status, loadMore } = useUIMessages(
api.chat.listMessages,
{ threadId },
{ initialNumItems: 20 }
);typescript
import { listUIMessages, paginationOptsValidator } from '@convex-dev/agent';
export const listMessages = query({
args: { threadId: v.string(), paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
return await listUIMessages(ctx, components.agent, args);
}
});React Hook:
typescript
import { useUIMessages } from '@convex-dev/agent/react';
const { results, status, loadMore } = useUIMessages(
api.chat.listMessages,
{ threadId },
{ initialNumItems: 20 }
);Agent Configuration Options
Agent 配置选项
typescript
const agent = new Agent(components.agent, {
name: 'Agent Name',
languageModel: openai.chat('gpt-4o-mini'),
textEmbeddingModel: openai.embedding('text-embedding-3-small'),
instructions: 'System prompt...',
tools: {
/* tools */
},
stopWhen: stepCountIs(10), // Or maxSteps: 10
// Context options (see CONTEXT.md)
contextOptions: {
recentMessages: 100,
excludeToolMessages: true,
searchOptions: { limit: 10, textSearch: false, vectorSearch: false }
},
// Storage options
storageOptions: { saveMessages: 'promptAndOutput' }, // 'all' | 'none'
// Handlers
usageHandler: async (ctx, { usage, model, provider, agentName }) => {},
contextHandler: async (ctx, { allMessages }) => allMessages,
rawRequestResponseHandler: async (ctx, { request, response }) => {},
// Call settings
callSettings: { maxRetries: 3, temperature: 1.0 }
});typescript
const agent = new Agent(components.agent, {
name: 'Agent Name',
languageModel: openai.chat('gpt-4o-mini'),
textEmbeddingModel: openai.embedding('text-embedding-3-small'),
instructions: 'System prompt...',
tools: {
/* tools */
},
stopWhen: stepCountIs(10), // Or use maxSteps: 10
// 上下文选项(参见CONTEXT.md)
contextOptions: {
recentMessages: 100,
excludeToolMessages: true,
searchOptions: { limit: 10, textSearch: false, vectorSearch: false }
},
// 存储选项
storageOptions: { saveMessages: 'promptAndOutput' }, // 'all' | 'none'
// 处理器
usageHandler: async (ctx, { usage, model, provider, agentName }) => {},
contextHandler: async (ctx, { allMessages }) => allMessages,
rawRequestResponseHandler: async (ctx, { request, response }) => {},
// 调用设置
callSettings: { maxRetries: 3, temperature: 1.0 }
});Key References
关键参考文档
- Streaming - Delta streaming, HTTP streaming, text smoothing
- Tools - Defining and using tools with Convex context
- Context - Customizing LLM context and RAG
- Threads - Thread management and deletion
- Messages - Message storage, ordering, UIMessage type
- Workflows - Durable multi-step workflows
- Human Agents - Mixing human and AI responses
- Files - Images and files in messages
- RAG - Retrieval-augmented generation patterns
- Rate Limiting - Controlling request rates
- Usage Tracking - Token usage and billing
- Debugging - Troubleshooting and playground
- Streaming - Delta流式输出、HTTP流式输出、文本平滑
- Tools - 结合Convex上下文定义和使用工具
- Context - 自定义LLM上下文和RAG
- Threads - 线程管理与删除
- Messages - 消息存储、排序、UIMessage类型
- Workflows - 可靠的多步骤工作流
- Human Agents - 混合人工与AI响应
- Files - 消息中的图片与文件
- RAG - 检索增强生成模式
- Rate Limiting - 控制请求速率
- Usage Tracking - Token使用量与计费
- Debugging - 故障排查与测试环境
Best Practices
最佳实践
- Define agents at module level - Reuse across functions
- Use on threads - Enables cross-thread search and per-user data
userId - Set appropriate /
stopWhen- Prevents runaway tool loopsmaxSteps - Use for async - Enables safe retries without duplicates
promptMessageId - Save messages in mutations - Use optimistic updates, schedule actions
- Use for RAG - Required for vector search
textEmbeddingModel - Handle streaming via deltas - Better UX than HTTP streaming alone
- 在模块级别定义Agent - 在多个函数中复用
- 为线程设置- 支持跨线程搜索和按用户划分数据
userId - 设置合适的/
stopWhen- 防止工具调用进入无限循环maxSteps - 异步场景使用- 支持安全重试,避免重复
promptMessageId - 在mutation中保存消息 - 使用乐观更新,调度Action
- 使用实现RAG - 向量搜索必需
textEmbeddingModel - 通过Delta处理流式输出 - 比仅使用HTTP流式输出的用户体验更好