1. 项目概述:从零开始,用Amazon Bedrock构建你的第一个AI智能体

如果你对生成式AI充满好奇,看着ChatGPT、Midjourney这些工具觉得神奇,但又觉得它们像是“黑盒子”,不知道如何将其能力整合到自己的应用或工作流中,那么你找对地方了。今天,我们不谈那些遥不可及的算法,也不讲复杂的模型训练,我们就从一个最实际的问题出发: 如何亲手搭建一个能理解你、并为你完成特定任务的AI智能体?

这个问题的答案,就藏在Amazon Bedrock里。简单来说,Bedrock不是一个单一的AI模型,而是一个“AI模型超市”兼“开发工具箱”。它把Anthropic的Claude、Meta的Llama、Cohere的Command等业界顶尖的大语言模型(LLM)以及图像生成模型,以API服务的形式提供给你。你不需要操心动辄数百GB的模型文件怎么下载,也不用担心需要价值数万美元的GPU来运行,更不用从零开始学习如何调优一个万亿参数的大模型。Bedrock让你能像调用任何其他云服务一样,直接使用这些强大的AI能力。

本教程的目标非常明确: 带领一位完全的初学者,从写下第一个提示词(Prompt)开始,步步为营,最终构建出一个能自动处理任务的AI智能体。 我们将使用Bedrock中最易上手的Claude模型,因为它以强大的逻辑推理和指令遵循能力著称,非常适合新手。整个旅程,你将亲身体验如何将一段简单的文本对话,升级为一个可以集成到网站、内部系统或自动化脚本中的“智能员工”。无论你是开发者、产品经理、业务分析师还是创业者,这篇手把手的指南都将为你打开一扇通往AI应用开发的大门。

2. 核心概念与Bedrock环境初探

在开始敲代码之前,我们必须先统一“语言”,理解几个核心概念,并准备好我们的“数字工作台”——AWS环境。

2.1 关键概念解析:提示词、模型与智能体

提示词(Prompt) :这是你与AI模型沟通的全部指令。你可以把它想象成给一位非常聪明但缺乏背景知识的实习生下达的工作说明。一个糟糕的提示词如“总结一下”,模型可能不知所云。而一个好的提示词会遵循“角色-任务-上下文-格式”的结构,例如:“你是一位专业的科技文章编辑,请将下面这篇关于云计算的博客草稿,总结成一份不超过200字的要点列表,面向CEO阅读,突出成本与效率收益。”

大语言模型(LLM) :如Claude、Llama,它们是经过海量文本训练而成的“大脑”,能够理解提示词并生成连贯、相关的文本回复。在Bedrock中,你通过选择不同的模型来获得不同的“性格”和能力倾向,比如有些更擅长创意写作,有些更精于代码生成。

AI智能体(AI Agent) :这是我们的终极目标。一个智能体不仅仅是能回答问题的聊天机器人。它是一个 具备目标导向、能自主规划步骤、调用工具(API)、并持续执行直到完成任务 的系统。例如,一个“智能客服工单处理Agent”在收到用户描述的问题后,会自主决定:先调用知识库API搜索解决方案,若未找到,则调用创建工单API,并自动填写分类、优先级和问题摘要。

Amazon Bedrock 扮演的角色就是让构建这样的智能体变得可行。它提供了模型API、知识库集成、以及工作流编排能力,将复杂的AI系统工程简化为可配置、可组合的服务。

2.2 AWS环境准备与Bedrock启用

首先,你需要一个AWS账户。如果还没有,可以去AWS官网注册,新用户通常有一定额度的免费资源。登录AWS管理控制台后,请按以下步骤操作:

  1. 区域选择 :在控制台右上角,选择一个 已支持Amazon Bedrock服务的区域 ,例如“美国东部(弗吉尼亚北部)us-east-1”或“亚太地区(新加坡)ap-southeast-1”。这是关键一步,Bedrock并非在所有区域开放。

  2. 搜索并进入Bedrock :在控制台顶部的服务搜索栏中,输入“Bedrock”并进入该服务。

  3. 模型访问请求 :首次进入Bedrock,你可能会看到模型列表显示为“未授予访问权限”。出于合规和负责任AI的考虑,AWS默认不开放所有模型。你需要手动申请访问。点击“模型访问”或类似标签页,找到你想要的模型,例如“Anthropic Claude 3 Sonnet”,点击“请求模型访问”。申请理由可以填写“学习与测试AI智能体开发”,通常几分钟到几小时内就会获批。

  4. 创建IAM用户与密钥(安全最佳实践) 绝对不建议 直接使用根账户的密钥进行开发。我们应该创建一个具有编程访问权限的IAM用户。

    • 在AWS控制台搜索“IAM”。
    • 在“用户”页面,点击“创建用户”。
    • 输入用户名,例如 bedrock-tutorial-user
    • 在“选择凭证类型”中,勾选“访问密钥 - 编程访问”。
    • 在权限设置中,点击“直接附加现有策略”,搜索并选择 AmazonBedrockFullAccess 策略(为简化教程,我们授予完整权限。在生产环境中,应根据最小权限原则创建自定义策略)。
    • 完成用户创建后, 务必立即下载或复制保存生成的“访问密钥ID”和“秘密访问密钥” 。这串密钥对只会显示一次,丢失后需要重新生成。
  5. 本地环境配置 :在你的开发机器上,安装AWS CLI,并通过 aws configure 命令,输入上一步获得的密钥、区域(如 us-east-1 )和默认输出格式(如 json )。这将为后续的SDK调用提供认证凭证。

注意 :保管好你的秘密访问密钥,如同保管密码。切勿将其提交到Git等代码仓库中。一个常见的做法是使用环境变量或AWS的密钥管理服务来安全地处理它们。

3. 第一步:与Claude进行第一次对话

现在,让我们真正开始与AI对话。我们将使用AWS SDK for Python (Boto3) 来调用Bedrock API。如果你更熟悉JavaScript/Node.js,其逻辑也完全相通。

3.1 安装依赖与基础调用脚本

首先,确保你的Python环境已安装boto3库。在终端中运行:

pip install boto3

接下来,创建一个名为 first_conversation.py 的文件,写入以下代码:

import json
import boto3
from botocore.config import Config

# 创建Bedrock运行时客户端,明确指定区域
bedrock_runtime = boto3.client(
    service_name='bedrock-runtime',
    region_name='us-east-1', # 请替换为你申请模型的区域
    config=Config(read_timeout=300) # 设置较长的超时时间,因为模型推理可能需要时间
)

# 定义我们的第一个提示词
prompt = """Human: 你好,Claude。请用中文简单介绍一下你自己,并告诉我你最擅长做什么。

Assistant:"""

# 构造请求体,这里我们使用Claude模型约定的消息格式
body = json.dumps({
    "anthropic_version": "bedrock-2023-05-31",
    "max_tokens": 1000,
    "messages": [
        {
            "role": "user",
            "content": [{"type": "text", "text": prompt}]
        }
    ]
})

# 指定模型ID
model_id = 'anthropic.claude-3-sonnet-20240229-v1:0'

try:
    # 调用模型
    response = bedrock_runtime.invoke_model(
        body=body,
        modelId=model_id
    )
    
    # 解析响应
    response_body = json.loads(response.get('body').read())
    # Claude的响应在 content 字段中
    output_text = response_body['content'][0]['text']
    print("Claude 的回答:")
    print(output_text)
    
except Exception as e:
    print(f"调用失败: {e}")

运行这个脚本 ( python first_conversation.py ),你应该会收到Claude一段礼貌的自我介绍。恭喜你,你已经成功通过代码调用了世界顶级的AI模型!这看似简单的一步,是后面所有复杂应用的基础。

3.2 理解请求与响应:消息格式与参数

让我们拆解一下上面代码中的关键部分:

  • bedrock-runtime 客户端 :我们使用它来调用模型的“推理”功能,即发送提示词并获取回复。
  • 请求体(Body) :这是与模型沟通的核心协议。不同模型的请求体格式可能不同。对于Claude,我们使用了Anthropic Messages API格式。其中:
    • max_tokens : 限制模型回复的最大长度(约等于单词数)。设置一个合理的值可以控制成本(Bedrock按输入输出总Token数计费)和响应时间。
    • messages : 一个包含对话历史的列表。每条消息都有 role (“user”或“assistant”)和 content 。这种结构使得进行多轮对话变得非常容易。
  • 模型ID :每个模型在Bedrock中都有唯一的ID。你可以在Bedrock控制台的“Playground”或文档里找到所有可用的模型ID。

实操心得 :在开发初期,强烈建议使用Bedrock控制台内置的 Playground 。它提供了一个交互式界面,让你可以可视化地调整提示词、系统指令(System Prompt)、温度(Temperature)等参数,并立即看到效果,而无需反复修改和运行代码。调试好提示词后,再将配置迁移到代码中,效率倍增。

4. 进阶:构建一个任务规划与执行智能体

现在,我们不再满足于单次问答。我们要创建一个能处理复杂任务的智能体。假设我们想构建一个“旅行规划助手”,它的任务是:根据用户模糊的需求,生成一个结构化的旅行计划。

4.1 设计系统提示词与任务拆解

智能体的“大脑”和“性格”由 系统提示词(System Prompt) 决定。它会在用户对话开始前被注入模型,设定上下文、角色和行为准则。

创建一个新文件 travel_agent.py ,我们先定义核心的系统提示词:

SYSTEM_PROMPT = """你是一个专业、细心且富有创见的旅行规划专家,名为“途悦助手”。你的核心职责是帮助用户制定详细、可行且个性化的旅行计划。

你必须遵循以下工作流程:
1. **需求澄清**:用户最初的需求可能很模糊(如“我想去个暖和的地方玩几天”)。你必须通过提问,主动澄清以下关键信息:
   - 旅行时间(几月、周末/工作日、具体天数)
   - 出发城市/国家
   - 旅行预算范围(经济/舒适/奢侈)
   - 旅行者类型(独自/情侣/家庭/朋友,是否有老人小孩)
   - 兴趣偏好(自然风光/城市人文/美食购物/冒险运动/休闲放松)
   - 任何特殊要求(如签证、无障碍设施、宠物友好)

2. **计划生成**:在获得足够信息后,生成一份结构化的旅行计划,必须包含:
   - **目的地建议**:给出1-3个具体目的地选项,并简述推荐理由。
   - **每日行程**:按天编排,包含上午、下午、晚上的活动建议,活动之间预留合理的交通和休息时间。
   - **预算估算**:对机票、住宿、餐饮、门票、交通进行分项粗略估算,并给出总预算区间。
   - **行前准备清单**:列出签证、衣物、药品、必备APP等物品。
   - **备选方案**:为可能出现的天气变化或突发情况(如景点关闭)提供备选活动。

3. **输出格式**:你的最终计划请用清晰的Markdown格式输出,并使用适当的标题(##、###)和列表来组织内容,使其易于阅读。

请记住,在用户未提供完整信息前,不要急于生成完整计划。优先通过提问来收集信息。每次回复请保持友好、热情且专业的口吻。
"""

这个系统提示词定义了智能体的角色、工作流程、输出规范。一个好的系统提示词是智能体成功的一半。

4.2 实现多轮对话与状态管理

智能体需要记住对话历史。我们将实现一个简单的对话循环。

import json
import boto3
from botocore.config import Config

class TravelPlanningAgent:
    def __init__(self):
        self.bedrock_runtime = boto3.client('bedrock-runtime', region_name='us-east-1')
        self.model_id = 'anthropic.claude-3-sonnet-20240229-v1:0'
        self.conversation_history = [
            {
                "role": "system",
                "content": [{"type": "text", "text": SYSTEM_PROMPT}]
            }
        ]
    
    def add_user_message(self, text):
        """添加用户消息到历史记录"""
        self.conversation_history.append({
            "role": "user",
            "content": [{"type": "text", "text": text}]
        })
    
    def get_agent_response(self):
        """调用模型,获取助手回复,并自动将回复加入历史"""
        # 构建请求体,这次我们发送整个对话历史
        body = json.dumps({
            "anthropic_version": "bedrock-2023-05-31",
            "max_tokens": 2000,
            "messages": self.conversation_history
        })
        
        try:
            response = self.bedrock_runtime.invoke_model(
                body=body,
                modelId=self.model_id
            )
            response_body = json.loads(response.get('body').read())
            assistant_message = response_body['content'][0]['text']
            
            # 将模型的回复也加入历史,以维持对话上下文
            self.conversation_history.append({
                "role": "assistant",
                "content": [{"type": "text", "text": assistant_message}]
            })
            
            return assistant_message
            
        except Exception as e:
            return f"抱歉,规划助手暂时出了点问题: {e}"
    
    def run_conversation(self):
        """运行一个简单的命令行对话循环"""
        print("途悦旅行规划助手已启动!请输入您的旅行需求(例如:'我想在国庆节期间出去玩'),输入'退出'结束。")
        print("-" * 50)
        
        while True:
            user_input = input("\n您: ")
            if user_input.lower() in ['退出', 'exit', 'quit']:
                print("感谢使用途悦助手,祝您旅途愉快!")
                break
                
            self.add_user_message(user_input)
            print("\n助手正在思考...")
            response = self.get_agent_response()
            print(f"\n途悦助手: {response}")

# 运行智能体
if __name__ == "__main__":
    agent = TravelPlanningAgent()
    agent.run_conversation()

运行这个脚本,你就可以在终端里与你的旅行规划智能体对话了。它会按照系统提示词的要求,先向你提问澄清需求,待信息齐全后,生成一份详细的Markdown格式旅行计划。

注意事项 :这个简单的状态管理( conversation_history )在单次会话中有效。对于Web应用,你需要为每个用户会话单独维护一个历史记录对象,通常存储在数据库或缓存中(如Redis)。同时,历史记录会消耗Token,成本会随对话轮次增加,过长的历史也可能触及模型的上下文窗口限制(Claude 3 Sonnet约20万Token)。对于超长对话,需要考虑摘要历史或采用更高级的“记忆”管理策略。

5. 从对话到智能体:集成外部工具与知识

真正的智能体不仅能说,还能“做”。它需要能调用外部工具(API)来获取实时信息或执行操作。例如,我们的旅行助手如果能查询实时天气、机票价格或酒店空房,计划将更具实用性。Bedrock通过 “工具调用(Tool Use)” 功能来支持这一点。

5.1 为Claude定义可用的工具

我们将为智能体增加两个工具: get_weather (获取天气)和 search_flights (搜索航班)。首先,我们需要以模型能理解的格式描述这些工具。

更新 TravelPlanningAgent 类的初始化部分,定义工具列表:

self.tools = [
    {
        "name": "get_weather",
        "description": "根据城市名称和日期,查询该地点的天气预报信息。",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "城市名称,例如:北京、东京、纽约"
                },
                "date": {
                    "type": "string",
                    "description": "查询的日期,格式为YYYY-MM-DD。默认为未来三天内。"
                }
            },
            "required": ["city"]
        }
    },
    {
        "name": "search_flights",
        "description": "根据出发地、目的地和日期,搜索航班选项。",
        "input_schema": {
            "type": "object",
            "properties": {
                "departure_city": {
                    "type": "string",
                    "description": "出发城市机场代码或名称,例如:PEK(北京首都), NYC(纽约)"
                },
                "arrival_city": {
                    "type": "string",
                    "description": "到达城市机场代码或名称"
                },
                "departure_date": {
                    "type": "string",
                    "description": "出发日期,格式为YYYY-MM-DD"
                }
            },
            "required": ["departure_city", "arrival_city", "departure_date"]
        }
    }
]

5.2 实现工具调用与响应处理循环

现在,我们需要修改 get_agent_response 方法,使其能够处理模型提出的工具调用请求。这涉及到一个循环:模型可能返回普通文本,也可能返回一个“我想调用某个工具”的请求,我们需要执行工具,并将结果返回给模型,让它继续思考。

def get_agent_response(self):
    """调用模型,处理可能的工具调用请求"""
    max_turns = 5  # 防止无限循环,限制工具调用轮次
    for turn in range(max_turns):
        # 构建请求,这次包含工具定义
        body = json.dumps({
            "anthropic_version": "bedrock-2023-05-31",
            "max_tokens": 2000,
            "tools": self.tools,
            "messages": self.conversation_history
        })
        
        try:
            response = self.bedrock_runtime.invoke_model(body=body, modelId=self.model_id)
            response_body = json.loads(response.get('body').read())
            
            # 检查响应内容
            for content_block in response_body['content']:
                if content_block['type'] == 'text':
                    # 普通文本回复,直接返回
                    assistant_message = content_block['text']
                    self.conversation_history.append({
                        "role": "assistant",
                        "content": [{"type": "text", "text": assistant_message}]
                    })
                    return assistant_message
                    
                elif content_block['type'] == 'tool_use':
                    # 模型请求使用工具
                    tool_name = content_block['name']
                    tool_input = content_block['input']
                    tool_call_id = content_block['id']
                    
                    print(f"\n[助手决定调用工具: {tool_name}, 参数: {tool_input}]")
                    
                    # 执行对应的工具函数
                    tool_result = self.execute_tool(tool_name, tool_input)
                    
                    # 将工具执行结果作为新的消息追加到历史中,供模型继续使用
                    self.conversation_history.append({
                        "role": "assistant",
                        "content": [content_block]  # 包含工具调用请求
                    })
                    self.conversation_history.append({
                        "role": "user",
                        "content": [{
                            "type": "tool_result",
                            "tool_use_id": tool_call_id,
                            "content": tool_result
                        }]
                    })
                    
                    # 工具调用后,跳出本次回复,进入下一轮循环,让模型基于工具结果继续思考
                    break
            else:
                # 如果循环正常结束(没有break),说明没有工具调用,直接返回文本
                # 这里需要处理可能没有文本块的情况(理论上不会发生)
                return "未收到有效回复。"
                
        except Exception as e:
            return f"调用过程出错: {e}"
    
    return "工具调用轮次过多,已终止。"

def execute_tool(self, tool_name, tool_input):
    """模拟执行工具并返回结果。在实际应用中,这里应调用真实的API。"""
    if tool_name == "get_weather":
        city = tool_input.get('city', '未知城市')
        date = tool_input.get('date', '近期')
        # 模拟API返回
        return f"模拟数据:{date},城市{city}的天气预计为晴朗,气温20-28摄氏度,微风。适宜出行。"
        
    elif tool_name == "search_flights":
        dep = tool_input.get('departure_city')
        arr = tool_input.get('arrival_city')
        date = tool_input.get('departure_date')
        # 模拟API返回
        return f"模拟数据:找到从{dep}到{arr}在{date}的航班。最早一班为08:00起飞,经济舱价格约1200元起。"
        
    else:
        return f"错误:未知工具 '{tool_name}'"

现在,当你再次运行智能体并提到具体目的地和日期时,它可能会主动说:“让我先为您查询一下那里的天气情况。” 随后,在后台,它会调用 get_weather 工具,获取模拟的天气数据,并基于此数据优化它的旅行建议(例如,“天气晴朗,我建议您增加户外活动”)。

实操心得 :工具调用是构建实用智能体的关键。在设计工具时,描述( description )和参数模式( input_schema )必须清晰准确,这直接决定了模型能否正确理解和使用它。初期可以先使用模拟函数(Stub)快速验证逻辑,待流程跑通后,再替换为真实的第三方API(如航司、天气服务商)或内部系统接口。

6. 生产级考量:安全、成本与部署

一个能在实验环境运行的智能体,与一个能投入生产使用的服务之间,还存在一些必须跨越的鸿沟。

6.1 安全与内容过滤

生成式AI可能产生不受控的输出。Bedrock提供了内置的 内容安全过滤器 。你可以在调用 invoke_model 时,在请求体中配置 guardrailIdentifier 来应用预定义的护栏策略,或者在Bedrock控制台中创建自定义护栏,过滤暴力、仇恨、性暗示或隐私信息等内容。

# 在请求体中可添加护栏配置(假设你已创建了护栏并获取了其ID)
body = json.dumps({
    "anthropic_version": "bedrock-2023-05-31",
    "max_tokens": 1000,
    "messages": [...],
    "guardrail": {
        "identifier": "your-guardrail-id",
        "version": "DRAFT"  # 或具体的版本号
    }
})

此外,对于处理用户输入,永远要遵循 最小权限原则 。智能体调用的工具API,其权限应被严格限制。例如,一个“邮件总结助手”不应该有权限通过工具发送邮件。

6.2 成本监控与优化

Bedrock按Token(输入+输出)计费,不同模型单价不同。Claude 3 Sonnet比Haiku贵,但能力更强。优化成本的方法包括:

  • 缓存(Caching) :对相同或相似的提示词和上下文,缓存模型的输出结果,避免重复计算。
  • 提示词工程 :精简你的系统提示词和用户输入,去除不必要的修饰语。
  • 设置Token上限 :合理设置 max_tokens ,避免模型生成冗长无关的内容。
  • 使用更经济的模型 :对于简单任务,可以使用Claude 3 Haiku这类更轻量、更便宜的模型。
  • 启用Bedrock的按请求跟踪 :在AWS Cost Explorer中,你可以通过标签或使用Bedrock的计量功能,详细监控每个应用、每个模型的调用成本。

6.3 部署模式与架构建议

一个简单的生产架构可能如下:

  1. 前端 :一个Web应用(如React/Vue)或聊天界面。
  2. 后端API :使用AWS Lambda(无服务器函数)或Amazon ECS/Fargate(容器服务)来运行我们上面编写的智能体逻辑。Lambda非常适合突发、无状态的对话请求。
  3. 会话状态管理 :使用Amazon DynamoDB(NoSQL数据库)或ElastiCache(Redis)来存储每个用户会话的 conversation_history 。键可以是 user_id:session_id
  4. 工具API集成 :在Lambda函数或单独的微服务中,实现调用真实天气、航班、酒店等第三方API的逻辑。使用AWS Secrets Manager安全地存储API密钥。
  5. 异步处理 :对于耗时的任务(如生成长篇报告),可以让智能体发起一个异步工作流,通过Amazon Step Functions进行编排,完成后通过WebSocket或轮询通知前端。

6.4 常见问题与排查技巧实录

在实际操作中,你几乎一定会遇到下面这些问题。这里是我的实战记录:

问题现象 可能原因 排查步骤与解决方案
调用API返回 AccessDeniedException 1. IAM用户/角色没有Bedrock权限。
2. 未在目标区域申请模型访问。
3. 凭证配置错误。
1. 检查IAM策略是否已附加 AmazonBedrockFullAccess 或相应权限。
2. 登录Bedrock控制台,确认当前区域下目标模型状态为“已授予访问权限”。
3. 运行 aws sts get-caller-identity 确认当前CLI凭证身份和区域。
模型响应慢或超时 1. 提示词过长或 max_tokens 设置过高。
2. 模型负载高。
3. 网络延迟。
1. 优化提示词,减少不必要内容。设置合理的 max_tokens
2. 在 boto3.client 初始化时增加 read_timeout connect_timeout 参数。
3. 考虑使用响应更快的模型变体(如Haiku)或启用流式响应以提升感知速度。
模型输出不符合预期(胡言乱语或拒绝回答) 1. 系统提示词定义不清或冲突。
2. 温度(Temperature)参数过高,导致随机性大。
3. 对话历史混乱,包含矛盾信息。
1. 在Playground中反复调试系统提示词,确保指令清晰、无歧义。使用“思考链”(Chain-of-Thought)风格提示词引导模型。
2. 在请求体中尝试添加 "temperature": 0.5 (值越低,输出越确定;越高,越有创造性)。
3. 清理或重置对话历史。对于长对话,尝试让模型自己总结之前的上下文。
工具调用不触发或参数错误 1. 工具描述不够清晰。
2. 输入模式(Schema)定义太严格或太宽松。
3. 模型当前上下文不足以决定调用工具。
1. 用更详细、具体的语言重写工具 description ,说明何时、为何使用此工具。
2. 检查 input_schema ,确保 required 字段合理, properties 的描述能帮助模型理解参数格式(如“日期格式为YYYY-MM-DD”)。
3. 在用户消息中提供更明确的、包含工具所需参数的信息。
成本增长过快 1. 对话历史未清理,每次请求Token数累积。
2. 频繁调用大模型处理简单任务。
1. 实现对话历史摘要功能:当历史达到一定长度,让模型生成一个简短摘要,然后用摘要替换旧历史。
2. 引入路由逻辑:简单查询(如FAQ)先用关键词匹配或小模型处理,复杂任务再交给Claude等大模型。

最后再分享一个小技巧 :在开发初期,不要急于追求完美的智能体。采用“快速迭代”的方式:先构建一个能跑通核心流程的最小可行产品(MVP),比如一个能进行三轮对话并调用一次工具的智能体。然后,带着这个MVP去找目标用户(哪怕是同事)试用,收集反馈。你会发现,最大的挑战往往不是技术实现,而是如何设计提示词和工具,让智能体的行为更符合用户的直觉和预期。这个过程,本身就是一个与AI协作、不断学习和调优的旅程,而这正是构建AI应用最迷人的部分。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐