本指南帮助 Closer Code 项目的工程师更好地使用
@anthropic-ai/sdk简化 AI API 调用,降低封装成本。
npm install @anthropic-ai/sdk// 手动实现 fetch、流式处理、错误处理...
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey,
'anthropic-version': '2023-06-01'
},
body: JSON.stringify(requestBody)
});
// 手动解析响应...import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY
});
const message = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
messages: [{ role: 'user', content: 'Hello, Claude!' }]
});
console.log(message.content);优势:
- ✅ 无需手动处理 HTTP 请求
- ✅ 自动类型检查
- ✅ 内置错误处理和重试
- ✅ 代码量减少 80%
| 功能 | 原生实现 | SDK 实现 |
|---|---|---|
| 代码行数 | ~40 行 | ~5 行 |
| SSE 解析 | 手动实现 | 自动处理 |
| 错误处理 | 手动处理 | 内置支持 |
| 类型安全 | 无 | 完整类型 |
// ai-client.js: streamFetch 函数
async function streamFetch(url, options, onChunk) {
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.text();
throw new Error(`API error: ${response.status} - ${error}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.trim().startsWith('data: ')) {
const data = line.trim().slice(6);
if (data === '[DONE]') continue;
try {
const parsed = JSON.parse(data);
onChunk(parsed);
} catch (e) {
// 忽略解析错误
}
}
}
}
}const stream = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
messages: [{ role: 'user', content: 'Hello!' }],
stream: true
});
for await (const event of stream) {
console.log(event.type);
}代码减少:87.5%
| 功能 | 原生实现 | SDK 实现 |
|---|---|---|
| 工具定义 | 手动构建 schema | 支持多种 schema 格式 |
| 工具调用循环 | 手动实现 | 自动处理 |
| 结果传递 | 手动管理 | 自动传递 |
| 代码量 | ~100 行 | ~20 行 |
// 手动处理工具调用
async function executeTools(aiClient, messages, tools) {
let currentMessages = [...messages];
while (true) {
const response = await aiClient.chat(currentMessages, { tools });
const toolResults = [];
for (const block of response.content) {
if (block.type === 'tool_use') {
const result = await executeTool(block.name, block.input);
toolResults.push({
role: 'tool',
toolUseId: block.id,
content: result
});
}
}
if (toolResults.length === 0) {
return response;
}
currentMessages.push({
role: 'assistant',
content: response.content
});
currentMessages.push(...toolResults);
}
}import { z } from 'zod';
import { betaZodTool } from '@anthropic-ai/sdk/helpers/beta/zod';
const weatherTool = betaZodTool({
name: 'get_weather',
description: '获取指定地点的天气',
inputSchema: z.object({
location: z.string().describe('城市名称')
}),
run: async (input) => {
// 执行工具逻辑
return `${input.location} 的天气是晴天,温度 20°C`;
}
});
const finalMessage = await client.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
messages: [{ role: 'user', content: '北京天气怎么样?' }],
tools: [weatherTool]
});代码减少:80%
| 功能 | 原生实现 | SDK 实现 |
|---|---|---|
| 格式转换 | 手动映射 | 类型安全 |
| 工具结果 | 特殊处理 | 标准格式 |
| 验证 | 运行时错误 | 编译时检查 |
// ai-client.js: 格式化消息
const formattedMessages = messages.map(m => {
if (m.role === 'tool') {
return {
role: 'user',
content: [{
type: 'tool_result',
tool_use_id: m.toolUseId,
content: m.content
}]
};
}
return {
role: m.role,
content: m.content
};
});import Anthropic from '@anthropic-ai/sdk';
// 完全类型安全,IDE 自动补全
const message: Anthropic.MessageParam = {
role: 'user',
content: 'Hello'
};
// 工具结果也是标准格式
const toolResult: Anthropic.ToolResultBlockParam = {
type: 'tool_result',
tool_use_id: 'toolu_xxx',
content: '执行结果'
};npm install @anthropic-ai/sdk之前(src/ai-client.js):
export class AnthropicClient {
constructor(config) {
this.apiKey = config.apiKey;
this.baseURL = config.baseURL || 'https://api.anthropic.com';
this.model = config.model || 'claude-sonnet-4-5-20250929';
this.maxTokens = config.maxTokens || 8192;
}
async chat(messages, options = {}) {
// ... 大量实现代码
}
}之后(src/ai-client-sdk.js):
import Anthropic from '@anthropic-ai/sdk';
export class AnthropicClientSDK {
private client: Anthropic;
private model: string;
private maxTokens: number;
constructor(config: { apiKey: string; model?: string; maxTokens?: number }) {
this.client = new Anthropic({
apiKey: config.apiKey
});
this.model = config.model || 'claude-sonnet-4-5-20250929';
this.maxTokens = config.maxTokens || 8192;
}
async chat(messages: Anthropic.MessageParam[], options?: {
system?: string;
tools?: Anthropic.Tool[];
temperature?: number;
}) {
return await this.client.messages.create({
model: this.model,
max_tokens: this.maxTokens,
system: options?.system,
messages,
tools: options?.tools,
temperature: options?.temperature
});
}
async chatStream(
messages: Anthropic.MessageParam[],
options?: { system?: string; tools?: Anthropic.Tool[] },
onChunk: (event: Anthropic.RawMessageStreamEvent) => void
) {
const stream = await this.client.messages.create({
model: this.model,
max_tokens: this.maxTokens,
system: options?.system,
messages,
tools: options?.tools,
stream: true
});
for await (const event of stream) {
onChunk(event);
}
}
}代码减少:70%
- 保留原有的
AnthropicClient类 - 新增
AnthropicClientSDK类 - 新功能使用 SDK,旧功能保持不变
- 创建适配器模式,统一接口
- 逐步将功能迁移到 SDK
- 充分测试兼容性
- 移除旧的实现代码
- 更新所有引用
- 清理依赖
import Anthropic from '@anthropic-ai/sdk';
// 基础配置
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
baseURL: 'https://api.anthropic.com', // 可选
timeout: 60000 // 可选,默认 10 分钟
});
// 获取模型信息
const models = await client.models.list();
console.log(models.data);const message = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [{
role: 'user',
content: '你好,请介绍一下你自己'
}]
});
console.log(message.content[0].type); // 'text'
console.log(message.content[0].text); // 响应内容const message = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [{
role: 'user',
content: [
{
type: 'text',
text: '请描述这张图片'
},
{
type: 'image',
source: {
type: 'base64',
media_type: 'image/png',
data: 'iVBORw0KGgoAAAANSUhEUg...' // base64 编码的图片
}
}
]
}]
});const stream = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [{ role: 'user', content: '讲个故事' }],
stream: true
});
for await (const event of stream) {
switch (event.type) {
case 'text_block':
console.log('收到文本块');
break;
case 'content_block_delta':
console.log('内容增量:', event.delta.text);
break;
case 'message_stop':
console.log('消息结束');
break;
}
}const stream = client.messages.stream({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [{ role: 'user', content: '写一首诗' }]
})
.on('text', (text) => {
console.log('实时文本:', text);
})
.on('error', (error) => {
console.error('流式错误:', error);
})
.on('finalMessage', (message) => {
console.log('完整消息:', message);
});
await stream.finalMessage();import { z } from 'zod';
import { betaZodTool } from '@anthropic-ai/sdk/helpers/beta/zod';
// 方式 1:使用 Zod(推荐)
const searchTool = betaZodTool({
name: 'search_code',
description: '在代码库中搜索',
inputSchema: z.object({
query: z.string().describe('搜索关键词'),
file_type: z.string().optional().describe('文件类型')
}),
run: async (input) => {
// 执行搜索逻辑
const results = await searchInCodebase(input.query, input.file_type);
return JSON.stringify(results);
}
});
// 方式 2:使用 JSON Schema
const searchTool2: Anthropic.Tool = {
name: 'search_code',
description: '在代码库中搜索',
input_schema: {
type: 'object',
properties: {
query: {
type: 'string',
description: '搜索关键词'
},
file_type: {
type: 'string',
description: '文件类型'
}
},
required: ['query']
}
};// 方式 1:自动工具循环(推荐)
const finalMessage = await client.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
messages: [{ role: 'user', content: '搜索所有 TypeScript 文件中的 "API" 关键词' }],
tools: [searchTool]
});
// 方式 2:手动工具循环
const response = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
messages: [{ role: 'user', content: '搜索代码' }],
tools: [searchTool]
});
// 处理工具调用
let currentMessages = [{ role: 'user', content: '搜索代码' }];
for (const block of response.content) {
if (block.type === 'tool_use') {
// 执行工具
const result = await executeTool(block.name, block.input);
// 返回结果
const toolResponse = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
messages: [
...currentMessages,
{ role: 'assistant', content: response.content },
{
role: 'user',
content: [{
type: 'tool_result',
tool_use_id: block.id,
content: result
}]
}
]
});
}
}// 在发送消息前计算 token 数量
const tokenCount = await client.messages.countTokens({
model: 'claude-sonnet-4-5-20250929',
messages: [
{ role: 'user', content: '这是一段很长的文本...' }
]
});
console.log('输入 tokens:', tokenCount.input_tokens);
// 从响应中获取使用信息
const message = await client.messages.create({...});
console.log('输入 tokens:', message.usage.input_tokens);
console.log('输出 tokens:', message.usage.output_tokens);Extended Thinking 是 Claude 的高级功能,允许模型在生成最终答案之前进行深度思考。当启用此功能时:
- 模型会使用指定的 token 预算进行内部推理
- 响应中会包含
thinking内容块,展示模型的思考过程 - 适用于复杂问题解决、代码分析、逻辑推理等场景
const message = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 3200,
// 启用扩展思考
thinking: {
type: 'enabled',
budget_tokens: 1600 // 为思考过程分配的 token 数量
},
messages: [{
role: 'user',
content: '分析这个复杂的算法问题:...'
}]
});
// 解析响应
for (const block of message.content) {
if (block.type === 'thinking') {
console.log('思考过程:', block.thinking);
console.log('签名:', block.signature);
} else if (block.type === 'text') {
console.log('最终答案:', block.text);
}
}重要参数说明:
budget_tokens: 思考过程的 token 预算- 最小值:1024 tokens
- 必须小于
max_tokens - 包含在
max_tokens限制内
type: 设置为'enabled'启用功能
const stream = client.messages.stream({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 3200,
thinking: {
type: 'enabled',
budget_tokens: 1600
},
messages: [{
role: 'user',
content: '解释量子纠缠的原理'
}]
})
.on('thinking', (thinking) => {
// 实时接收思考内容
process.stdout.write(thinking);
})
.on('text', (text) => {
// 接收最终答案
process.stdout.write(text);
})
.on('signature', (signature) => {
// 接收思考内容的签名
console.log('\n签名:', signature);
})
.on('error', (error) => {
console.error('错误:', error);
});
const finalMessage = await stream.finalMessage();
console.log('\n完整消息:', finalMessage);let thinkingState = 'not-started';
const stream = client.messages.stream({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 3200,
thinking: { type: 'enabled', budget_tokens: 1600 },
messages: [{ role: 'user', content: '你的问题' }]
})
.on('thinking', (thinking) => {
if (thinkingState === 'not-started') {
console.log('思考过程:\n---------');
thinkingState = 'started';
}
process.stdout.write(thinking);
})
.on('text', (text) => {
if (thinkingState !== 'finished') {
console.log('\n\n最终答案:\n-----');
thinkingState = 'finished';
}
process.stdout.write(text);
});
await stream.finalMessage();适合使用 Extended Thinking 的场景:
- 复杂问题分析:需要多步推理的问题
- 代码审查:深入分析代码逻辑和潜在问题
- 架构设计:权衡不同技术方案的优劣
- 调试协助:分析复杂 bug 的根本原因
- 算法优化:分析和改进算法效率
不推荐使用的场景:
- 简单问答(会增加成本和延迟)
- 创意写作(思考内容可能对最终输出帮助有限)
- 实时性要求极高的场景
// 根据问题复杂度动态调整 thinking budget
function calculateThinkingBudget(complexity: 'low' | 'medium' | 'high'): number {
const budgets = {
low: 1024, // 简单问题
medium: 2048, // 中等复杂度
high: 4096 // 复杂问题
};
return budgets[complexity];
}
const message = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
thinking: {
type: 'enabled',
budget_tokens: calculateThinkingBudget('high')
},
messages: [{ role: 'user', content: complexQuestion }]
});// 默认情况下,thinking 是禁用的
const message = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [{ role: 'user', content: '简单问题' }]
});
// 或者显式禁用
const message2 = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
thinking: { type: 'disabled' },
messages: [{ role: 'user', content: '简单问题' }]
});import {
APIError,
APIConnectionError,
RateLimitError,
AuthenticationError
} from '@anthropic-ai/sdk';
try {
const message = await client.messages.create({...});
} catch (error) {
if (error instanceof APIConnectionError) {
console.error('网络连接错误:', error.message);
} else if (error instanceof RateLimitError) {
console.error('速率限制,请稍后重试');
} else if (error instanceof AuthenticationError) {
console.error('API 密钥无效');
} else if (error instanceof APIError) {
console.error('API 错误:', error.message);
console.error('状态码:', error.status);
console.error('错误详情:', error.error);
}
}SDK 内置自动重试,但可以自定义:
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
maxRetries: 3, // 默认 2
timeout: 60000
});const message = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
system: '你是一个编程助手',
messages: [
{
role: 'user',
content: '分析这段代码'
}
],
// 启用提示缓存
cache_control: {
type: 'ephemeral',
ttl: '5m'
}
});// 使用 Message Batches API
const batch = await client.messages.batches.create({
requests: [
{
custom_id: 'request-1',
params: {
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [{ role: 'user', content: '任务 1' }]
}
},
{
custom_id: 'request-2',
params: {
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [{ role: 'user', content: '任务 2' }]
}
}
]
});
// 获取结果
const results = await client.messages.batches.results(batch.id);
for await (const result of results) {
console.log(result);
}// ✅ 好的做法:使用环境变量
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY
});
// ❌ 不好的做法:硬编码密钥
const client = new Anthropic({
apiKey: 'sk-ant-xxx...' // 不要这样做!
});// 验证用户输入
function sanitizeUserInput(input: string): string {
// 移除潜在的恶意内容
return input
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
.slice(0, 10000); // 限制长度
}
const message = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [{
role: 'user',
content: sanitizeUserInput(userInput)
}]
});问题:对话历史很长,导致 token 超限。
解决方案:
// 方案 1:使用 token 计数检查
async function checkTokenCount(messages: Anthropic.MessageParam[]) {
const count = await client.messages.countTokens({
model: 'claude-sonnet-4-5-20250929',
messages
});
if (count.input_tokens > 100000) {
// 截断或总结早期消息
return summarizeMessages(messages);
}
return messages;
}
// 方案 2:滑动窗口
function slidingWindow(messages: Anthropic.MessageParam[], maxMessages = 10) {
return messages.slice(-maxMessages);
}class Conversation {
private messages: Anthropic.MessageParam[] = [];
private system: string;
constructor(system: string) {
this.system = system;
}
async say(userMessage: string) {
this.messages.push({
role: 'user',
content: userMessage
});
const response = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
system: this.system,
messages: this.messages
});
this.messages.push({
role: 'assistant',
content: response.content
});
return response;
}
}
// 使用
const chat = new Conversation('你是一个编程助手');
await chat.say('什么是 TypeScript?');
await chat.say('能给我一个例子吗?');// 使用 Promise.all 并行处理
const tasks = [
'分析文件 A',
'分析文件 B',
'分析文件 C'
];
const results = await Promise.all(
tasks.map(task =>
client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [{ role: 'user', content: task }]
})
)
);
// 或者使用 Message Batches API(更适合大量请求)// 启用详细日志
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
// 添加日志中间件
baseURL: 'https://api.anthropic.com'
});
// 检查请求详情
const message = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [{ role: 'user', content: '测试' }]
}).withResponse();
console.log('响应头:', message.response.headers);
console.log('请求 ID:', message.response.headers.get('request-id'));import Anthropic from '@anthropic-ai/sdk';
import { betaZodTool } from '@anthropic-ai/sdk/helpers/beta/zod';
import { z } from 'zod';
// 初始化客户端
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY
});
// 定义工具
const readFileTool = betaZodTool({
name: 'read_file',
description: '读取文件内容',
inputSchema: z.object({
filePath: z.string().describe('文件路径')
}),
run: async (input) => {
const fs = await import('fs/promises');
const content = await fs.readFile(input.filePath, 'utf-8');
return content;
}
});
const writeFileTool = betaZodTool({
name: 'write_file',
description: '写入文件内容',
inputSchema: z.object({
filePath: z.string().describe('文件路径'),
content: z.string().describe('文件内容')
}),
run: async (input) => {
const fs = await import('fs/promises');
await fs.writeFile(input.filePath, input.content, 'utf-8');
return '文件已保存';
}
});
// 主函数
async function codeAssistant(userRequest: string) {
const finalMessage = await client.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
system: '你是一个专业的代码助手,可以帮助用户读写文件和分析代码。',
messages: [{ role: 'user', content: userRequest }],
tools: [readFileTool, writeFileTool]
});
return finalMessage;
}
// 使用示例
const result = await codeAssistant('请读取 src/index.js 文件并分析它的功能');
console.log(result.content);async function streamingCodeAssistant(userRequest: string) {
const stream = client.messages.stream({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
system: '你是一个专业的代码助手',
messages: [{ role: 'user', content: userRequest }],
tools: [readFileTool, writeFileTool]
})
.on('text', (text) => {
process.stdout.write(text);
})
.on('toolUse', (toolUse) => {
console.log('\n[执行工具]', toolUse.name, toolUse.input);
})
.on('error', (error) => {
console.error('\n[错误]', error);
});
const finalMessage = await stream.finalMessage();
return finalMessage;
}import * as readline from 'readline';
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
async function askQuestion(query: string): Promise<string> {
return new Promise(resolve => {
rl.question(query, (answer) => {
resolve(answer);
});
});
}
async function interactiveChat() {
const messages: Anthropic.MessageParam[] = [];
console.log('=== Closer Code 交互式对话 ===');
console.log('输入 "quit" 退出\n');
while (true) {
const userInput = await askQuestion('你: ');
if (userInput.toLowerCase() === 'quit') {
break;
}
messages.push({
role: 'user',
content: userInput
});
const stream = client.messages.stream({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 8192,
messages
})
.on('text', (text) => {
process.stdout.write(text);
})
.on('finalMessage', (msg) => {
messages.push({
role: 'assistant',
content: msg.content
});
});
await stream.finalMessage();
console.log('\n');
}
rl.close();
}
interactiveChat();这是一个展示如何使用 Extended Thinking 功能进行深度代码分析的完整示例:
import Anthropic from '@anthropic-ai/sdk';
import { betaZodTool } from '@anthropic-ai/sdk/helpers/beta/zod';
import { z } from 'zod';
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY
});
// 定义代码分析工具
const analyzeFileTool = betaZodTool({
name: 'analyze_file',
description: '读取并分析代码文件',
inputSchema: z.object({
filePath: z.string().describe('文件路径'),
analysisType: z.enum(['security', 'performance', 'readability', 'all'])
.describe('分析类型')
}),
run: async (input) => {
const fs = await import('fs/promises');
try {
const content = await fs.readFile(input.filePath, 'utf-8');
return {
success: true,
file: input.filePath,
content: content.slice(0, 5000), // 限制长度
analysisType: input.analysisType
};
} catch (error) {
return {
success: false,
error: (error as Error).message
};
}
}
});
// 代码审查助手类
class CodeReviewAssistant {
private client: Anthropic;
private model: string;
constructor() {
this.client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY
});
this.model = 'claude-sonnet-4-5-20250929';
}
// 使用 Extended Thinking 进行深度分析
async deepAnalysis(userRequest: string, complexity: 'low' | 'medium' | 'high' = 'high') {
const thinkingBudgets = {
low: 1024,
medium: 2048,
high: 4096
};
console.log(`\n=== 开始深度分析 (Thinking Budget: ${thinkingBudgets[complexity]} tokens) ===\n`);
let thinkingState = 'not-started';
let thinkingContent = '';
const stream = this.client.messages.stream({
model: this.model,
max_tokens: 8192,
thinking: {
type: 'enabled',
budget_tokens: thinkingBudgets[complexity]
},
system: `你是一个专业的代码审查专家。当分析代码时,你会:
1. 仔细阅读并理解代码逻辑
2. 识别潜在的安全漏洞
3. 分析性能问题
4. 提出改进建议
5. 解释你的推理过程`,
messages: [{ role: 'user', content: userRequest }],
tools: [analyzeFileTool]
})
.on('thinking', (thinking) => {
if (thinkingState === 'not-started') {
console.log('🤔 深度思考中...\n---');
thinkingState = 'started';
}
thinkingContent += thinking;
process.stdout.write(thinking);
})
.on('text', (text) => {
if (thinkingState !== 'finished') {
console.log('\n\n---\n✅ 分析结果:\n---');
thinkingState = 'finished';
}
process.stdout.write(text);
})
.on('toolUse', (toolUse) => {
console.log('\n\n🔧 使用工具:', toolUse.name);
console.log('参数:', JSON.stringify(toolUse.input, null, 2));
})
.on('error', (error) => {
console.error('\n❌ 错误:', error);
});
const finalMessage = await stream.finalMessage();
console.log('\n\n=== 分析完成 ===');
console.log(`思考内容长度: ${thinkingContent.length} 字符`);
console.log(`Token 使用: 输入=${finalMessage.usage.input_tokens}, 输出=${finalMessage.usage.output_tokens}`);
return {
finalMessage,
thinkingContent
};
}
// 快速分析(不使用 Extended Thinking)
async quickAnalysis(userRequest: string) {
console.log('\n=== 快速分析模式 ===\n');
const finalMessage = await this.client.beta.messages.toolRunner({
model: this.model,
max_tokens: 4096,
system: '你是一个代码审查助手,快速检查代码问题。',
messages: [{ role: 'user', content: userRequest }],
tools: [analyzeFileTool]
});
console.log('✅ 快速分析完成');
console.log(`Token 使用: 输入=${finalMessage.usage.input_tokens}, 输出=${finalMessage.usage.output_tokens}`);
return finalMessage;
}
}
// 使用示例
async function main() {
const assistant = new CodeReviewAssistant();
// 示例 1: 深度分析复杂代码
console.log('\n【示例 1: 深度安全分析】');
await assistant.deepAnalysis(
'请对 src/auth/login.ts 进行全面的安全分析,特别关注SQL注入、XSS和认证漏洞',
'high'
);
// 等待用户输入
await new Promise(resolve => setTimeout(resolve, 2000));
// 示例 2: 快速代码审查
console.log('\n\n【示例 2: 快速代码审查】');
await assistant.quickAnalysis('检查 src/utils/helpers.ts 中是否有明显的性能问题');
// 示例 3: 流式深度分析
console.log('\n\n【示例 3: 架构设计分析】');
const result = await assistant.deepAnalysis(
'分析当前项目的架构设计,评估可扩展性和维护性,并提供重构建议',
'high'
);
// 保存分析结果
if (result.thinkingContent) {
console.log('\n💡 提示: 思考过程已保存到 result.thinkingContent');
}
}
// 运行示例
if (require.main === module) {
main().catch(console.error);
}
export { CodeReviewAssistant };$ npm run code-review
=== 开始深度分析 (Thinking Budget: 4096 tokens) ===
🤔 深度思考中...
---
让我分析这段代码...
首先,我需要理解认证流程:
1. 用户提交登录表单
2. 验证用户名和密码
3. 生成会话令牌
在安全方面,我注意到:
- 密码应该使用哈希存储
- 需要防止暴力破解
- 应该实现速率限制
让我继续分析...
---
✅ 分析结果:
---
基于我的分析,我发现了以下安全问题:
1. **SQL 注入风险**: 在第 45 行,查询字符串拼接存在风险...
2. **会话管理**: 建议使用 HTTP-only cookies...
3. **速率限制**: 建议添加登录尝试限制...
=== 分析完成 ===
思考内容长度: 1243 字符
Token 使用: 输入=3456, 输出=789- 智能复杂度判断: 根据问题类型自动调整 thinking budget
- 实时反馈: 流式展示思考过程,提升用户体验
- 工具集成: 结合文件读取工具进行实际分析
- 成本优化: 对简单问题使用快速分析模式
- 复杂任务: 使用
high复杂度和较大的 thinking budget (4096+) - 中等任务: 使用
medium复杂度 (2048 tokens) - 简单任务: 考虑使用快速分析模式以节省成本
使用 @anthropic-ai/sdk 的核心优势:
- 代码量减少 70-80%
- 类型安全:完整的 TypeScript 支持
- 自动重试:内置错误处理和重试逻辑
- 流式响应简化:无需手动解析 SSE
- 工具执行自动化:toolRunner 自动处理工具调用
- 更好的性能:优化的网络请求和缓存支持
- Extended Thinking 支持:深度思考功能,解决复杂问题
- 实时思考过程:流式展示模型的推理过程
开始迁移建议:
- ✅ 从新功能开始使用 SDK
- ✅ 保留旧代码以确保稳定性
- ✅ 逐步迁移核心功能
- ✅ 充分测试后完全切换
文档版本: 1.1.0 最后更新: 2025-01-18 维护者: Closer Code 团队
更新记录:
- v1.1.0 (2025-01-18): 新增 Extended Thinking 功能完整说明和示例
- v1.0.0 (2025-01-17): 初始版本,涵盖基础 API 使用
参考资源: