2026年7月2日 周四晚上19:30,报名腾讯会议了解“如何构建自进化的动态知识库(Brain)”(限30人)
免费POC, 零成本试错
FDE知识库

FDE知识库

学习大模型的前沿技术与行业落地应用


收藏

Coze + Bot API:实现带自我反思的高质量长文翻译Agent(吴恩达方法)

发布日期:2024-07-17 09:02:28 浏览次数: 4599
作者:AI大模型应用实践

微信搜一搜,关注“AI大模型应用实践”


很多人熟悉的吴恩达老师前段时间发布了一个开源项目translation-agent,提出了一种利用LLM进行自我反思并完善的自动化长文翻译智能体,并给出了简单的原型代码,在国内也看到了开源RAG平台FastGPT对此流程的实现(一键生成高质量长文翻译,吴恩达新方法颠覆传统!)。于是我们尝试在Coze平台上类似的实现一个翻译智能体,本文将简单分享这个过程。

Translation-agent工作流程

我们都知道借助LLM与提示词可以很简单的让模型将一段文本从一种语言翻译成另外一种语言,而且一般质量还不错。但有时也会存在一些问题:

  • 翻译仍然会存在一些准确性、流畅度、文字风格等方面的不足

  • 涉及到长文本时,比如超出模型的最大输出tokens,处理较麻烦


Translation-agent采用的工作流程大致如下:

对短文本块(不超过最大允许的tokens数量)的翻译过程为:

  1. 通过提示词让LLM将文本从一种语言翻译到另外一种语言

  2. 让LLM对翻译的结果进行反思,提出各方面的改进建议

  3. 再次让LLM根据生成的改进建议对初始的翻译进行完善并输出


而对于长文本来说,只需要通过相应算法将长文本分割成相对均匀的小“文本块”,再对多个小文本块进行循环处理即可(循环的单文本块处理方法并不完全等同于直接的短文本块的一次性处理,后面会看到)。

接下来我们在Coze平台上来模拟实现这个翻译Agent,为了简化处理,这里直接把翻译语言固定成从英文翻译为中文,你当然可以根据需要把这两种语言做参数化,在使用时格式化到提示词中即可。

单文本块的翻译与反思

我们首先来构建单文本块的翻译与反思工作流。在Coze中创建一个新的工作流,然后开始配置:

【初始翻译】

创建大模型节点,并作如下配置,输入一个源文本,输出一个翻译文本,注意这里的提示词是比较简单的:

【反思】

将初始翻译的结果输入到反思节点,并配置反思的大模型提示。在原项目中,除了源语言和目标语言之外,还有一个国家的参数(country),这个参数用来生成更符合该国语言风格的翻译,此处我们也暂时忽略。输入参数是源文本与初步翻译的结果,输出参数是反思的建议:

【改进翻译】

通过模型的反思得到建议后,通过再次输入LLM要求根据反思建议进行改进,输出更加完善的翻译结果即可,这里需输入源文本、初始翻译结果以及改进建议三个参数:

【试运行】

我们选择一段Llama3的介绍英文来测试,使用国内的智谱GLM-4模型:

这里观察到在运行期间LLM给首次翻译提出的改进建议,客观的说,有的建议可能并非完全必要,但整体而言还是在上下文准确性、流畅度、减少重复上有相当的意义:

最终翻译输出的结果如下,还是非常流畅与到位的:

【组装到Bot】

现在,你可以创建一个工作流模式的单Agent的Bot,并把这个工作流指定给这个Bot,然后你就拥有一个会自我反思的翻译助手,当然这个助手还只能翻译不能太大的文本块:

长文本翻译处理

在学会了单文本块的反思与翻译以后,就可以在此基础上对长文本通过拆分与循环处理,并适当改造已有的单文本块提示,最终完成对长文本的高质量翻译。整个的处理逻辑是:

对长文本的tokens判断,如果数量超过指定的最大限制(比如1000),则将输入文本拆解成多个相对均匀的小文本块,并确保大小不超过限制,然后对多个文本块进行循环处理。很显然,多文本块的处理应该是可以兼容单个文本块的处理(原项目中做了区分)。

由于目前Coze的工作流编排暂时还不支持循环,所以无法直接编排循环处理的工作流,这里我们借助Coze的Bot API,将此过程编码实现,通过循环调用前面的单文本块翻译的Bot来实现。

对长文本下的单文本块处理并不简单等同于直接的短文本块处理,主要原因是为了给长文本下的单个文本块增加足够的上下文,使得翻译的更加准确且一致。主要区别就是在输入完整的源文本(source_text标签部分)中标识了本次需要翻译的文本块(translate_this)标签,并提示LLM只对translate_this部分做处理,这样既提供了足够的上下文,又只翻译了本次处理的文本块。以初始化翻译为例,你需要对上面创建的单文本块bot提示做如下修改:


你是一个把英文文本转化成简体中文的翻译助手。

源文本如下,以XML标签<SOURCE_TEXT>和</SOURCE_TEXT>分隔。

你只需要翻译源文本中以<TRANSLATE_THIS>和</TRANSLATE_THIS>分隔的部分;您可以将其余部分作为上下文,但不要翻译其他文本。

不要输出任何除指定部分的翻译之外的内容。不要有多余解释。不要重复原文。

--------

英文文本:{{source_text}}

中文文本:

再次重申,仅翻译<TRANSLATE_THIS>和</TRANSLATE_THIS>之间的文本。


反思与完善的环节处理方式类似。通过这样处理后的Bot既可以支持直接的短文本块处理(给全部文本添加<TRANSLATE_THIS>标签);也可以支持长文本下的单个文本块循环处理(给每次需要处理的文本块增加<TRANSLATE_THIS>标签)

【Bot API准备】

现在的Coze平台支持API调用,通过API可以访问云端创建的Bot与工作流、对话、管理知识库等,大大扩展了Coze的应用场景。这里我们先把上面创建的单文本块的Bot发布成API,首先需要申请API调用的令牌

然后将自己的Bot进行发布,发布时选择“Bot as API”的模式,并等待审核通过即可,现在你就可以通过API调用你自己的Bot免费用Coze平台的大模型:

【调用Bot】

在客户端创建一个简单的函数来调用自己的Bot API,参考Coze的文档实现即可,由于我们做了简化,只需要传入一个需要翻译的源文本即可。注意由于Coze采用的异步API,所以需要多次调用:

import requests
import time
import json
import re
import tiktoken
from langchain_text_splitters import TokenTextSplitter

ACCESS_TOKEN = "***"
BOT_ID = "***"
USER_ID = "***"

def call_coze_api(query):
    
    url = 'https://api.coze.cn/v3/chat'
    headers = {
        'Authorization': f'Bearer {ACCESS_TOKEN}',
        'Content-Type': 'application/json'
    }
    payload = {
        "bot_id": BOT_ID,
        "user_id": USER_ID,
        "stream": False,
        "auto_save_history": True,
        "additional_messages": [
            {
                "role": "user",
                "content": query,
                "content_type": "text"
            }
        ]
    }

    response = requests.post(url, headers=headers, json=payload)
    
    if response.status_code == 200:

        response_data = response.json().get('data')
        id = response_data['id']
        conversation_id = response_data['conversation_id']

        retrieve_url = f'https://api.coze.cn/v3/chat/retrieve?chat_id={id}&conversation_id={conversation_id}'
        while True:

            print('Starting retrieve the response...')
            retrieve_response = requests.get(retrieve_url, headers=headers)
            if retrieve_response.status_code == 200:
                retrieve_data = retrieve_response.json().get('data')
                if retrieve_data['status'] == 'completed':

                    result_url = f'https://api.coze.cn/v3/chat/message/list?chat_id={id}&conversation_id={conversation_id}'
                    result_response = requests.get(result_url, headers=headers)
                    if result_response.status_code == 200:
                        result_data = result_response.json().get('data')
                        result_dict = next((item for item in result_data if item['type'] == 'answer'), None)
                        return result_dict.get('content')
                    else:
                        print(f"Error: {result_response.status_code}, {result_response.text}")
                        return {"error": result_response.status_code, "message": result_response.text}
                    
            else:
                print(f"Error: {retrieve_response.status_code}, {retrieve_response.text}")
                return {"error": retrieve_response.status_code, "message": retrieve_response.text}
            
            time.sleep(10) # Add a delay to avoid excessive API calls
    else:
        print(f"Error: {response.status_code}, {response.text}")
        return {"error": response.status_code, "message": response.text}

【几个辅助函数】

实现tokens计算、chunk_size计算,以及chunks分割的三个辅助函数。基本思想是:

  • tokens计算:借助tiktoken库实现

  • chunk_size计算:根据最大tokens限制来计算每个chunk的size

  • chunks分割:输入text与计算出的chunk_size,借助langchain做分割,并保证句子完整性


def token_count(text):
    encoding = tiktoken.get_encoding("gpt2")
    tokens = encoding.encode(text)
    token_count = len(tokens)
    return token_count

def calculate_chunk_size(token_count: int, token_limit: int) -> int:
    if token_count <= token_limit:
        return token_count
    num_chunks = (token_count + token_limit - 1) // token_limit
    chunk_size = token_count // num_chunks
    remaining_tokens = token_count % token_limit
    if remaining_tokens > 0:
        chunk_size += remaining_tokens // num_chunks
    return chunk_size

def get_text_chunks(text,chunk_size) : 
    splitter = TokenTextSplitter(
        chunk_size=int(chunk_size),
        chunk_overlap=0,
    )
    initial_chunks = splitter.split_text(text)  
    # 定义不同语言的句子分隔符
    sentence_delimiters = re.compile(r'[。!?.!?]')
    # 进一步处理每个初步分割块
    output = []
    current_chunk = initial_chunks[0] if initial_chunks else ''
    for i in range(1, len(initial_chunks)):
        sentences = sentence_delimiters.split(initial_chunks[i])
        if sentences:
            current_chunk += sentences[0] # 拼接第一个句子到当前块
            output.append(current_chunk.strip()) # 将当前块加入输出数组
            current_chunk = ''.join(sentences[1:]) # 剩余的句子作为新的当前块
    # 将最后一个块加入输出数组
    if current_chunk.strip():
        output.append(current_chunk.strip())       
    return output

【主程序】

主程序的逻辑非常简单:

  1. 读取需要翻译的文件内容

  2. 计算tokens、chunk_size,并进行分割,形成多个文本块

  3. 调用Bot API循环处理多个文本块

  4. 合并结果,输出翻译后的文件


这里的代码中有两种循环处理单个文本块的方式:一种不考虑上下文,另外一种考虑上下文,即每次只处理<translate_this>标签部分,并把其他部分作为上下文输入。

# 示例调用
with open('source.txt', 'r') as file:
    query = file.read().strip()

#tokens计算、chunk_size计算、分割chunks
token_count = token_count(query)
chunk_size = calculate_chunk_size(token_count, 800)
chunks = get_text_chunks(query,chunk_size)

results = []
for index in range(len(chunks)):
    tagged_text = chunks[index]
    """
    如果需要增加上下文,采用如下方式;注意需要提示词配合
    tagged_text = (
            "".join(chunks[0:index])
            + "<TRANSLATE_THIS>"
            + chunks[index]
            + "</TRANSLATE_THIS>"
            + "".join(chunks[index + 1 :])
    )
    """

    result = call_coze_api(tagged_text)
    result_dict =json.loads(result)
    results.append(result_dict.get('output'))

output = " ".join(results)
with open('target.txt', 'w') as file:
    file.write(output)

这样就实现了一个带有自我反思与提升功能的长文本翻译Agent。整个过程逻辑还是比较清楚的,在实际测试中遇到的主要问题是LLM遵循性的问题,偶尔会出现不够遵循指令,比如在输出中出现多余的解释说明,特别是在完善环节以及多文本块处理时,偶尔会有错误的输出。

这个Agent暂时还只能处理纯文本的输入,后续可以结合多模态的处理技术实现更复杂的文档完整翻译功能,比如图表结合的PDF文档。在原项目中,作者也对后续的优化提出了一些思路,比如测试更多的LLM、增加对特定词汇表(针对特定国家或行业)的支持等,我们期待看到更多有益的尝试与测试结果。





交流请识别以下名片并说明来源

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询

扫码登录
登录即表示您同意《53AI网站服务协议》
服务协议

欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。

在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。

一、 定义

本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。

会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。

知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。

二、 账号注册与登录

登录方式:本网站支持以下登录方式,您可根据实际情况选择:

微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。

手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。

账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。

实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。

未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。

三、 服务内容与规范

知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。

服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。

禁止行为:您在使用服务时不得实施以下行为:

利用技术手段批量爬取、下载、转存知识库内容;

将知识库内容用于商业目的或未经授权地向第三方传播;

干扰本网站正常运行或侵犯其他用户合法权益;

发布违法违规信息或从事违反公序良俗的活动。

四、 知识产权声明

权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。

有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。

侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。

五、 个人信息保护

我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。

您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。

您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。

六、 免责声明

内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。

不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。

第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。

七、 违约责任

如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。

如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。

八、 法律适用与争议解决

本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。

因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。

九、 其他

本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。

本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。

我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。


已查阅