ปัจจุบัน วงการ AI Agent กำลังเผชิญกับสถานการณ์ที่ค่อนข้างน่าอึดอัดใจ นั่นคือการแยกส่วนกันอย่างชัดเจนระหว่างขั้นตอนการอนุมาน (Inference) ที่ต้องพึ่งพาเฟรมเวิร์กหนึ่ง และขั้นตอนการฝึก (Training) ที่ต้องเปลี่ยนไปใช้อีกเฟรมเวิร์กหนึ่ง ท่อส่งข้อมูล (Data Pipeline), สิ่งที่เป็นนามธรรมของสภาพแวดล้อม (Environment Abstraction) และอินเทอร์เฟซเครื่องมือ (Tool Interface) ระหว่างทั้งสองนี้แทบจะไม่เข้ากันเลย
นั่นหมายความว่า หลังจากที่นักวิจัยได้ตรวจสอบความสามารถในการอนุมานของ Agent ตัวหนึ่งแล้ว หากต้องการปรับปรุงมันให้ดียิ่งขึ้นด้วยการเรียนรู้แบบเสริมกำลัง (Reinforcement Learning) พวกเขาก็จำเป็นต้องเขียนตรรกะการโต้ตอบทั้งหมดขึ้นมาใหม่ตั้งแต่ต้น กระบวนการนี้ไม่เพียงแต่ใช้เวลามหาศาล แต่ยังง่ายต่อการนำบั๊กที่เกิดจากความไม่สอดคล้องกันในรูปแบบต่างๆ ที่คาดไม่ถึงเข้ามาอีกด้วย
เพื่อแก้ไขความขัดแย้งพื้นฐานนี้ Uni-Agent จึงได้ถือกำเนิดขึ้น มันนำเสนอ Unified Interaction Stack เพื่อให้แน่ใจว่า Agent จะใช้เส้นทางโค้ดที่เหมือนกันทุกประการเมื่อทำการอนุมานและเมื่อทำการฝึกด้วยการเรียนรู้แบบเสริมกำลัง
ปรัชญาการออกแบบหลักของมันคือการแยกส่วนออกเป็นสามชั้น: model รับผิดชอบการคิด, tool รับผิดชอบการรับรู้และการกระทำ, env รับผิดชอบการคงสถานะไว้ ทั้งสามส่วนนี้สามารถถูกแทนที่ได้อย่างอิสระ และยังสามารถประกอบเข้าด้วยกันได้อย่างราบรื่น ด้วยกลไกการควบคุมการทำงานพร้อมกันแบบสัญญาณอะซิงโครนัส (Asynchronous Semaphore) Uni-Agent จึงทำงานได้อย่างเสถียรในระดับการทำงานพร้อมกันมากกว่า 1,000 งาน และ ทำคะแนนได้สูงถึง 67.7 บน SWE-Bench-Verified
รูปด้านล่างแสดงสถาปัตยกรรมโดยรวมของระบบ Agent Uni-Agent ซึ่งแบ่งออกเป็นสองโมดูลหลักอย่างชัดเจน: การโต้ตอบและการทำงาน (Interaction & Execution) และการฝึกโมเดล (Model Training) Agent Interaction System ในชั้นบนเป็นแกนหลักของวงจรการทำงาน: Agent Chat Model (ที่รวมเอาโมเดลขนาดใหญ่ชั้นนำหลายตัว) เรียกใช้ความสามารถต่างๆ จาก Tools Pool เช่น เครื่องมือพัฒนา เบราว์เซอร์ ฯลฯ เพื่อระบุหรือแก้ไข Environment (เช่น แผงตรวจสอบ บริการคลาวด์ สภาพแวดล้อมคอนเทนเนอร์) การเปลี่ยนแปลงสถานะของสภาพแวดล้อมจะถูกส่งกลับไปยังโมเดล เพื่อสนับสนุนการตัดสินใจในขั้นตอนถัดไป Training System ในชั้นล่าง (ใช้ verl framework เป็นตัวอย่าง) รับผิดชอบการปรับแต่งโมเดล: เมื่อภารกิจเสร็จสิ้น Reward System จะสร้างสัญญาณรางวัล ส่งผ่าน Message Queue ไปยัง Training Engine ซึ่งจะอัปเดตน้ำหนักของ Agent Model ตามข้อมูลเหล่านี้ ทำให้ Agent สามารถพัฒนาความสามารถในการตัดสินใจได้อย่างต่อเนื่องผ่านการโต้ตอบและการฝึกฝนอย่างต่อเนื่อง ก่อให้เกิดห่วงโซ่ที่สมบูรณ์ตั้งแต่การดำเนินการไปจนถึงการตอบรับและการปรับปรุงซ้ำ
แผงตรวจสอบแบบน้ำหนักเบาของ Uni-Agent ส่วนบนแสดงสถานะโดยรวมของงานอย่างชัดเจน: มีทั้งหมด 500 งาน กำลังทำงาน 64 งาน รอคิว 339 งาน เสร็จสิ้น 97 งาน สะท้อนถึงคิวงานและความคืบหน้าของการดำเนินการได้อย่างชัดเจน แผงด้านซ้ายแสดง ID ของงานที่กำลังทำงานอยู่ทั้งหมดและขั้นตอนการดำเนินการปัจจุบัน แผงบันทึกสี่ช่องตรงกลางและด้านขวาจะแสดงห่วงโซ่การโต้ตอบที่สมบูรณ์ของ Agent แต่ละตัว ห่วงโซ่เหล่านี้ประกอบด้วย “ความคิด (Thought)”, “การกระทำ (Action เช่น การรันสคริปต์ Python, การรันคำสั่งทดสอบ pytest)”, “การสังเกต (Observation เช่น ข้อมูลข้อผิดพลาดของโค้ด, คำเตือนการเลิกใช้งาน, ข้อมูลการใช้ Token)” ซึ่งสร้างกระบวนการตัดสินใจ การดำเนินการตามคำสั่ง และการตอบรับจากสภาพแวดล้อมของ Agent ขึ้นมาใหม่ทั้งหมด ช่วยให้นักพัฒนาสามารถติดตามสถานะการทำงานของ Agent ในงานพัฒนาและดีบักได้แบบเรียลไทม์ และระบุจุดที่มีปัญหาได้อย่างรวดเร็ว ข้อมูลเพิ่มเติมสามารถดูได้ที่: แผงตรวจสอบแบบน้ำหนักเบาของ Uni-Agent[1]
unsetunsetสารบัญunsetunset
- เริ่มต้นใช้งานอย่างรวดเร็ว
- หนึ่ง ภาพรวมโครงสร้างโครงการ
- สอง ภาพรวมสถาปัตยกรรมและกระแสข้อมูลหลัก
- 2.1 ปรัชญาการออกแบบแบบแยกส่วนสามชั้น
- 2.2 กระแสข้อมูลของการโต้ตอบที่สมบูรณ์หนึ่งครั้ง
- สาม จุดเริ่มต้นแบบรวม: ตรรกะการจัดเรียงของ UniAgentLoop
- 3.1 การควบคุมการทำงานพร้อมกันและการแยกทรัพยากร
- 3.2 ขั้นตอนการดำเนินการหลัก
- 3.3 การลดระดับอย่างสง่างามสำหรับเส้นทางที่ผิดปกติ
- สี่ เอนจินการโต้ตอบ: วงจรหลายรอบของ AgentInteraction
- 4.1 โมเดลข้อมูล StepOutput
- 4.2 สายการผลิตห้าขั้นตอนของการโต้ตอบทีละขั้นตอน
- 4.3 กลไกงบประมาณหมดเวลา
- ห้า Rollout Cache: การสะสมข้อมูลการฝึกแบบเรียลไทม์
- 5.1 โครงสร้างข้อมูลหลัก
- 5.2 การสะสมระหว่างการสร้างโมเดล
- 5.3 การสะสมระหว่างการตอบรับจากสภาพแวดล้อม
- 5.4 การคำนวณที่แม่นยำของ Message Boundary Tokens
- หก สิ่งที่เป็นนามธรรมของสภาพแวดล้อม: AgentEnv และการปรับใช้หลายแบ็กเอนด์
- 6.1 อินเทอร์เฟซสภาพแวดล้อมแบบรวม
- 6.2 ยูเนียนจำแนกประเภทของแบ็กเอนด์การปรับใช้
- 6.3 RemoteRuntime: ชั้นการสื่อสาร HTTP ที่เชื่อถือได้
- 6.4 การจัดการหมดเวลาและการขัดจังหวะที่แข็งแกร่ง
- เจ็ด ระบบเครื่องมือ: ตั้งแต่การลงทะเบียนไปจนถึงการดำเนินการ
- 7.1 รูปแบบรีจิสทรี
- 7.2 ขั้นตอนการติดตั้งเครื่องมือ
- 7.3 การแปล Tool Call เป็น Bash
- 7.4 Tool Parser หลายรูปแบบ
- แปด ระบบรางวัล: การตรวจสอบภายในสภาพแวดล้อม
- 8.1 รีจิสทรีและคลาสพื้นฐานนามธรรม
- 8.2 รางวัล SWE-Bench: ขับเคลื่อนโดยกรณีทดสอบจริง
- เก้า auto_await: การเชื่อมต่อแบบซิงโครนัสและอะซิงโครนัสอย่างราบรื่น
- สิบ สิ่งที่เป็นนามธรรมของโมเดลคู่: ความเป็นหนึ่งเดียวของการฝึกและการอนุมานบริสุทธิ์
- 10.1 AgentChatModel vs OpenAICompatibleChatModel
- 10.2 การจัดการ Tool Call สำหรับโมเดลที่เข้ากันได้กับ OpenAI
- สิบเอ็ด โมเดลการทำงานพร้อมกันและวิศวกรรมประสิทธิภาพ
- 11.1 สถาปัตยกรรมอะซิงโครนัสแบบครบวงจร
- 11.2 ข้อมูลประสิทธิภาพที่สำคัญ
- สิบสอง การบันทึกผลลัพธ์และการสังเกตการณ์
- 12.1 การคงอยู่ของผลลัพธ์การโต้ตอบ
- 12.2 การอนุมานสถานะของ Dashboard
- สรุปและแนวโน้มในอนาคต
unsetunsetเริ่มต้นใช้งานอย่างรวดเร็วunsetunset
# โคลน repository และเริ่มต้นโมดูลย่อย
git clone https://github.com/verl-project/uni-agent.git
cd uni-agent
git submodule update --init --recursive
# ติดตั้ง verl (เป็น Python package)
pip install --no-deps -e ./verl
# ติดตั้ง dependencies หลัก
pip install swe-rex loguru pydantic pydantic_settings aiohttp
หลังจากติดตั้งเสร็จ คุณสามารถเริ่มสภาพแวดล้อม Agent และรันสคริปต์ตัวอย่างได้โดยตรง สำหรับการกำหนดค่าโดยละเอียดเพิ่มเติมเกี่ยวกับสถานการณ์อื่นๆ (เช่น การสร้าง Search Agent, การอนุมานแบบขนาน, การฝึก RL) โปรดดูเอกสารทางการ[2]
เริ่มแผงตรวจสอบแบบเรียลไทม์ด้วยคำสั่งต่อไปนี้:
python -m dashboard.server --log-dir /tmp/swebench_qwen3_coder --port 8765
สำหรับรายละเอียดการกำหนดค่าการส่งต่อพอร์ตระยะไกลและการผูกของ Dashboard โปรดดูเอกสาร dashboard/README.md[3]
หนึ่ง วิเคราะห์โครงสร้างโครงการแบบพาโนรามา
ก่อนที่จะลงลึกในรายละเอียดโค้ด เรามาทำความเข้าใจตรรกะการจัดระเบียบโดยรวมของโครงการผ่านแผนผังไดเรกทอรีกันก่อน:
uni-agent/
├── uni_agent/ # แพ็คเกจ Python หลัก
│ ├── agent_loop.py # จุดเริ่มต้นแบบรวม: UniAgentLoop (เชื่อมต่อการฝึก verl)
│ ├── async_logging.py # การบันทึกแบบอะซิงโครนัส (แยกตาม run_id)
│ ├── utils.py # ยูทิลิตี้เช่น auto_await
│ ├── interaction/ # ชั้นเอนจินการโต้ตอบ
│ │ ├── interaction.py # วงจรการโต้ตอบหลายรอบ AgentInteraction
│ │ ├── model.py # สิ่งที่เป็นนามธรรมของโมเดล (AgentChatModel / OpenAI Compatible)
│ │ ├── env.py # สิ่งที่เป็นนามธรรมของสภาพแวดล้อม AgentEnv (การดำเนินการ)
│ │ ├── tools_manager.py # การจัดการเครื่องมือและการแปลการเรียก
│ │ └── tool_parser.py # ตัวแยกวิเคราะห์รูปแบบการเรียกเครื่องมือ (XML/Hermes)
│ ├── tools/ # การใช้งานเครื่องมือเฉพาะ
│ │ ├── base.py # คลาสพื้นฐาน AbstractTool
│ │ ├── registry.py # รีจิสทรีเครื่องมือ
│ │ ├── execute_bash/ # เครื่องมือดำเนินการ Bash
│ │ ├── str_replace_editor/ # เครื่องมือแก้ไขไฟล์
│ │ ├── search/ # เครื่องมือค้นหาโค้ด
│ │ ├── search_arxiv/ # ค้นหาบทความ arXiv
│ │ ├── finish/ # เครื่องหมายเสร็จสิ้น
│ │ └── submit/ # เครื่องหมายส่ง
│ ├── deployment/ # แบ็กเอนด์การปรับใช้สภาพแวดล้อม
│ │ ├── config.py # การกำหนดค่าการปรับใช้แบบรวม (ยูเนียนจำแนกประเภท)
│ │ ├── remote_runtime.py # ไคลเอนต์ HTTP รันไทม์ระยะไกล
│ │ ├── host/ # โหมดดำเนินการโดยตรงบนโฮสต์
│ │ ├── local/ # แซนด์บ็อกซ์คอนเทนเนอร์ท้องถิ่น (Docker/Apptainer)
│ │ ├── modal/ # แพลตฟอร์มคลาวด์ Modal
│ │ └── vefaas/ # Volcengine FaaS
│ └── reward/ # โมดูลคำนวณรางวัล
│ ├── base.py # คลาสพื้นฐาน AbstractRewardSpec
│ ├── registry.py # รีจิสทรีฟังก์ชันรางวัล
│ ├── swe_bench.py # รางวัลประเมิน SWE-Bench
│ ├── swe_bench_live.py # รูปแบบ SWE-Bench Live
│ ├── swe_rebench.py # รูปแบบ SWE-ReBench
│ ├── r2e_gym.py # รางวัลฝึก R2E-Gym
│ └── search.py # รางวัล Search Agent
├── examples/ # สคริปต์ตัวอย่าง
│ ├── agent_env/ # ตัวอย่างเริ่มต้นสภาพแวดล้อม
│ ├── agent_interaction/ # ตัวอย่างการโต้ตอบแบบขนาน
│ ├── agent_train/ # สคริปต์ฝึก RL
│ ├── search_agent/ # การฝึก Search Agent
│ ├── search_arxiv/ # ตัวอย่าง arXiv Agent
│ └── data_preprocess/ # การประมวลผลข้อมูลล่วงหน้า
├── dashboard/ # แผงตรวจสอบแบบเรียลไทม์ (JS/CSS/Python server)
├── verl/ # Git submodule → volcengine/verl
├── docs/ # ซอร์สโค้ดเอกสาร Sphinx
└── pyproject.toml # ข้อมูลเมตาของแพ็คเกจและการพึ่งพา
สอง ภาพรวมสถาปัตยกรรมและกระแสข้อมูลหลัก
2.1 แนวคิดการออกแบบแบบแยกส่วนสามชั้น
การออกแบบโดยรวมของ Uni-Agent สามารถแสดงให้เห็นได้ผ่านแผนภาพสถาปัตยกรรมต่อไปนี้:
แผนภาพแสดงการแบ่งหน้าที่ของสามโมดูลหลักอย่างชัดเจน:
- Model (เอนจินการอนุมาน): โมดูลนี้ห่อหุ้มการโต้ตอบการอนุมานกับ Large Language Model (LLM) มีหน้าที่ดูแล Rollout Cache (ประกอบด้วยลำดับ Token, Mask และ Logprobs) ในโหมดฝึก มันสามารถเชื่อมต่อกับเซิร์ฟเวอร์ AsyncLLM ของ verl framework ได้อย่างราบรื่น ในขณะที่ในสถานการณ์การอนุมานบริสุทธิ์ มันเข้ากันได้กับ API ใดๆ ที่เป็นไปตามมาตรฐานอินเทอร์เฟซของ OpenAI
- Tool (ชั้นการรับรู้และการดำเนินการ): หน้าที่หลักของโมดูลนี้คือการแปลคำสั่งเรียกเครื่องมือ (tool call) ที่มีโครงสร้างซึ่งสร้างโดยโมเดลให้เป็นคำสั่ง bash ที่เฉพาะเจาะจง เครื่องมือเหล่านี้ถูกติดตั้งในคอนเทนเนอร์ที่รันในรูปแบบของสคริปต์ที่สามารถดำเนินการได้
- Env (แซนด์บ็อกซ์รันไทม์): โมดูลนี้สื่อสารกับคอนเทนเนอร์หรือแซนด์บ็อกซ์ระยะไกลผ่านโปรโตคอล SWE-ReX คุณสมบัติที่สำคัญคือความสามารถในการรองรับแบ็กเอนด์การปรับใช้สี่แบบและสลับไปมาระหว่างกันได้อย่างราบรื่น
2.2 การวิเคราะห์กระแสข้อมูลการโต้ตอบที่สมบูรณ์หนึ่งครั้ง
ภายใต้กรอบงานของ Uni-Agent การโต้ตอบของ Agent ที่สมบูรณ์หนึ่งครั้งจะเป็นไปตามกระแสข้อมูลที่ชัดเจนและสามารถวนซ้ำได้ กระบวนการทั้งหมดเริ่มต้นจากจุดเข้า UniAgentLoop ผ่านการวนซ้ำหลายขั้นตอนภายในโมดูล AgentInteraction และในที่สุดก็สร้างเอาต์พุตที่มีโครงสร้างซึ่งสามารถใช้สำหรับการฝึกเรียนรู้แบบเสริมกำลัง
ขั้นตอนเฉพาะมีดังนี้:
1. สอบถามโมเดล (Query Model): ระบบจะส่งประวัติการสนทนาปัจจุบันพร้อมกับคำแนะนำงานเป็นอินพุตไปยังโมดูล AgentChat Model
2. แยกวิเคราะห์การเรียกเครื่องมือ (Parse Tool Call): หากการตอบสนองที่ส่งกลับโดยโมเดลมีคำสั่งเรียกเครื่องมือ โมดูล AgentInteraction จะแยกวิเคราะห์เป็นคำขอ Tool Call ที่มีโครงสร้าง
3. ดำเนินการในสภาพแวดล้อม (Execute in Env): การเรียกเครื่องมือที่แยกวิเคราะห์แล้วจะถูกส่งต่อไปยัง AgentEnv เพื่อดำเนินการตามคำสั่งที่เกี่ยวข้อง (เช่น รันคำสั่ง bash) ในคอนเทนเนอร์ โฮสต์ระยะไกล หรือสภาพแวดล้อมท้องถิ่นจริง
4. สังเกตและผนวก (Observe & Append): หลังจากสภาพแวดล้อมดำเนินการเสร็จสิ้น ผลลัพธ์การดำเนินการ (เช่น เอาต์พุตมาตรฐาน ข้อความแสดงข้อผิดพลาด) จะถูกส่งกลับเป็นผลการสังเกต (Observation) ผลการสังเกตนี้จะถูกผนวกเข้ากับประวัติการสนทนาเพื่อใช้เป็นอินพุตสำหรับการ Query Model ในครั้งถัดไป
ขั้นตอนข้างต้นจะ形成一个วงจร วนซ้ำอย่างต่อเนื่องจนกว่างานจะเสร็จสมบูรณ์ (done) หรือถึงจำนวนรอบสูงสุดที่กำหนดไว้ เมื่อวงจรสิ้นสุดลง ระบบจะเข้าสู่ขั้นตอนต่อไปนี้:
- การประเมินรางวัล (RewardSpec): โมดูล
RewardSpecจะให้คะแนนและประเมินกระบวนการโต้ตอบทั้งหมดของ Agent ตามเกณฑ์การประเมินที่กำหนดไว้ล่วงหน้าภายในสภาพแวดล้อม - การจัดรูปแบบเอาต์พุต (AgentLoopOutput): สุดท้าย โมดูล
AgentLoopOutputจะ打包ข้อมูลสำคัญต่างๆ เช่นprompt,response,maskและlogprobsจากกระบวนการโต้ตอบทั้งหมดให้เป็นเอาต์พุตมาตรฐาน เอาต์พุตนี้สามารถป้อนเข้าสู่กรอบงานฝึกเรียนรู้แบบเสริมกำลังverlได้โดยตรงเพื่อใช้ในการปรับแต่งโมเดลให้ดียิ่งขึ้น
มาดูเส้นทางการทำงานที่สมบูรณ์ของ Agent ตั้งแต่รับงานไปจนถึงสร้างข้อมูลการฝึก:
ผู้ใช้ Prompt (messages)
│
▼
┌─ prepare_rollout_cache ─┐ เข้ารหัส messages เป็นลำดับ token
│ prompt_ids = tokenize │ เริ่มต้น response_mask/logprobs ที่ว่างเปล่า
└─────────┬───────────────┘
│
┌─────▼─────┐
│ STEP 1 │◀───────────────────────────────────────┐
├───────────┤ │
│ model.query() │
│ → response_ids (mask=1, บันทึก logprobs) │
│ │
│ tools_manager.parse_action() │
│ → ดึงชื่อฟังก์ชัน + อาร์กิวเมนต์ │
│ │
│ tools_manager.get_tool_bash_command() │
│ → แปลงเป็นสตริงคำสั่ง bash │
│ │
│ env.run_action() │
│ → สตริง observation │
│ │
│ model.append_messages_to_rollout_cache() │
│ → ผนวกการเข้ารหัส observation (mask=0) │
│ │
│ done? ──No──────────────────────────────────────────┘
│ │
│ Yes
└───┬───┘
│
▼
┌─ reward_spec.compute_reward() ─┐ รันการทดสอบในคอนเทนเนอร์เดียวกัน
│ เช่น: ดำเนินการสคริปต์ทดสอบ SWE-Bench │ และแยกวิเคราะห์รายงานการทดสอบ
└────────────┬───────────────────┘
│
▼
┌─ convert_to_agent_output() ──┐ แยก prompt/response
│ ประกอบ AgentLoopOutput │ ใช้ mask_abnormal_exit
│ → ส่งออกให้ verl ทำ PPO/GSPO │ ตัดลำดับที่ยาวเกินไป
└──────────────────────────────┘
สิ่งที่ชาญฉลาดที่สุดในกระบวนการนี้คือ การสะสม Rollout Cache แบบเรียลไทม์ — ซึ่งทำให้การโต้ตอบครั้งเดียวสามารถทั้ง “ดำเนินการอนุมาน” และ “รวบรวมข้อมูลการฝึก” ได้พร้อมกัน โดยไม่จำเป็นต้องมีขั้นตอนหลังการประมวลผลเพิ่มเติมใดๆ
สาม จุดเริ่มต้นแบบรวม: ตรรกะการจัดเรียงของ UniAgentLoop
3.1 การควบคุมการทำงานพร้อมกันและการแยกทรัพยากร
UniAgentLoopทำหน้าที่เป็นสะพานเชื่อมระหว่าง Uni-Agent และกรอบงานฝึก verl มันสืบทอดมาจากAgentLoopBaseของ verl และถูกเรียกใช้ในช่วง rollout ของการฝึกเรียนรู้แบบเสริมกำลัง:
# ที่มา: uni_agent/agent_loop.py
class UniAgentLoop(AgentLoopBase):
_semaphore: asyncio.Semaphore | None = None # แชร์ในระดับคลาส
async def run(self, sampling_params: dict[str, Any], **kwargs) -> AgentLoopOutput:
config_dict = self._init_config(sampling_params, **kwargs)
# การทำงานพร้อมกันทั่วโลกเฉลี่ยตามจำนวน worker
global_concurrent = config_dict.get("concurrency", 512)
num_workers = self.config.actor_rollout_ref.rollout.agent.num_workers
worker_concurrent = max(global_concurrent // num_workers, 1)
if UniAgentLoop._semaphore is None:
UniAgentLoop._semaphore = asyncio.Semaphore(worker_concurrent)
ที่นี่ _semaphore ถูกกำหนดให้เป็นตัวแปรคลาส อินสแตนซ์ UniAgentLoop ทั้งหมดใช้สัญญาณเดียวกัน สมมติว่าขีดจำกัดการทำงานพร้อมกันทั่วโลกตั้งไว้ที่ 512 และมี 4 worker ในระบบ ดังนั้นแต่ละ worker สามารถรันสภาพแวดล้อมได้สูงสุด 128 ตัวพร้อมกัน กลไกนี้ป้องกันข้อผิดพลาด OOM หรือความล้มเหลวในการจัดตารางคอนเทนเนอร์ที่เกิดจากการโอเวอร์โหลดของทรัพยากรได้อย่างมีประสิทธิภาพ
3.2 ขั้นตอนการดำเนินการหลัก
# ที่มา: uni_agent/agent_loop.py
async with self._semaphore:
try:
await self.env.start() # เริ่มแซนด์บ็อกซ์
self.chat_model.set_tools_schemas(...) # ใส่ tool schema
await self.env.install_tools(self.tools_manager.tools) # ติดตั้งเครื่องมือในคอนเทนเนอร์
interaction_result = await self.interaction.run() # วงจรการโต้ตอบหลัก
# คำนวณรางวัลภายในสภาพแวดล้อม (สภาพแวดล้อมยังไม่ปิด)
if self.reward_spec is not None:
reward_score, _ = await self.reward_spec.compute_reward(
interaction_result=interaction_result,
)
interaction_result["reward_score"] = reward_score
self._save_interaction_result(interaction_result)
output = await self.convert_to_agent_output(interaction_result)
except Exception as e:
output = await self._build_empty_agent_output(exit_reason="agent_loop_failed")
finally:
await self.env.close() # ปิดสภาพแวดล้อมไม่ว่าจะสำเร็จหรือล้มเหลว
return output
บล็อก finally ที่นี่รับประกันว่าสภาพแวดล้อมจะถูกทำความสะอาดอย่างแน่นอน — ในสถานการณ์การทำงานพร้อมกันระดับพัน คอนเทนเนอร์ที่ไม่ได้ปล่อยจะทำให้ทรัพยากรคลัสเตอร์หมดลงอย่างรวดเร็ว
3.3 การลดระดับอย่างสง่างามสำหรับเส้นทางที่ผิดปกติ
เมื่อการโต้ตอบของ Agent ออกผิดปกติ ระบบจะไม่ทิ้งข้อมูลนี้ แต่จะสร้าง “เส้นทางว่าง” และใส่เครื่องหมายปิดบัง:
# ที่มา: uni_agent/agent_loop.py
async def _build_empty_agent_output(self, exit_reason: str) -> AgentLoopOutput:
# เติมด้วย pad_token หรือ eos_token
dummy_token_id = getattr(self.tokenizer, "pad_token_id", None)
if dummy_token_id is None:
dummy_token_id = getattr(self.tokenizer, "eos_token_id", None)
extra_fields["traj_masked"] = 1 # ข้ามเส้นทางนี้ระหว่างการฝึก
extra_fields["traj_exit_reason"] = exit_reason
return AgentLoopOutput(
response_ids=[dummy_token_id] * dummy_response_length,
response_mask=[0] * dummy_response_length, # ศูนย์ทั้งหมด → ไม่เข้าร่วม gradient
reward_score=0,
...
)
ด้วยวิธีนี้ ความสม่ำเสมอของรูปร่าง batch การฝึกจึงได้รับการรับประกัน — ไม่จำเป็นต้องมีการ padding แบบไดนามิกหรือความผันผวนของขนาด batch
สี่ เอนจินการโต้ตอบ: วงจรหลายรอบของ AgentInteraction
4.1 โมเดลข้อมูล StepOutput
แต่ละขั้นตอนการโต้ตอบจะสร้าง StepOutput ที่มีโครงสร้าง:
# ที่มา: uni_agent/interaction/interaction.py
class StepOutput(BaseModel):
step_idx: int
response: str = "" # เอาต์พุตดิบของโมเดล
thought: str = "" # เนื้อหาความคิด (ข้อความก่อน tool_call)
action: str = "" # คำสั่ง bash ที่แปลงแล้ว
observation: str = "" # สิ่งที่สภาพแวดล้อมส่งกลับ
execution_time: float | None = None
done: bool = False
exit_reason: str = "" # finished/token_limit/timeout_error/...
### 4.2 สายการผลิตห้าขั้นตอนของการโต้ตอบทีละขั้นตอน
```python
# ที่มา: uni_agent/interaction/interaction.py
async def step(self, step_idx: int):
step_output = StepOutput(step_idx=step_idx)
# ── ขั้นตอนที่ 1: การอนุมานโมเดล ──
model_output, rollout_cache, generation_info = await self.model.query(
messages=self.messages, rollout_cache=self.rollout_cache,
)
# ── ขั้นตอนที่ 2: แยกวิเคราะห์ Tool Call ──
self.messages.append({"role": "assistant", "content": model_output})
structured_tool_calls = self.rollout_cache.get("extra_fields", {}).get("last_tool_calls", [])
if structured_tool_calls:
# รูปแบบ tool_calls ดั้งเดิมของ OpenAI (สถานการณ์การอนุมาน)
content, tool_calls = await self.tools_manager.parse_structured_action(
content=model_output, tool_calls_data=structured_tool_calls,
)
else:
# แยกวิเคราะห์รูปแบบ XML/Hermes จากข้อความ (สถานการณ์การฝึก)
content, tool_calls = await self.tools_manager.parse_action(model_output=model_output)
# ── ขั้นตอนที่ 3: แปลงเป็นคำสั่ง Bash ──
tool_call = tool_calls[0]
action_cmd = self.tools_manager.get_tool_bash_command(tool_call)
# ── ขั้นตอนที่ 4: ดำเนินการในสภาพแวดล้อม ──
observation = await self.env.run_action(action_cmd, action_timeout=self.action_timeout)
tool_message = {"role": "tool", "content": observation}
self.messages.append(tool_message)
self.rollout_cache = await self.model.append_messages_to_rollout_cache(
[tool_message], self.rollout_cache
)
# ── ขั้นตอนที่ 5: ตัดสินเงื่อนไขการสิ้นสุด ──
if tool_call.function.name in ["finish", "submit"]:
step_output.done = True
step_output.exit_reason = "finished"
กระบวนการทั้งหมดสามารถแสดงได้ดังนี้:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Model │───▶│ Parse │───▶│ Translate│───▶│ Execute │───▶│ Judge │
│ Query │ │ ToolCall │ │ to Bash │ │ in Env │ │ Done? │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
▲ │
└───────────────────── loop if not done ────────────────────────┘
4.3 กลไกงบประมาณหมดเวลา
การออกแบบที่ชาญฉลาดสำหรับการทนทานต่อข้อผิดพลาดปรากฏอยู่ใน
timeout_budget:
# ที่มา: uni_agent/interaction/interaction.py
except ActionTimeoutError as e:
step_output.exit_reason = "timeout_error"
if self.timeout_budget > 0:
self.timeout_budget -= 1
return step_output # ดำเนินการขั้นตอนต่อไป (ให้โอกาสโมเดลแก้ไข)
else:
step_output.done = True # หมดเวลาหมดแล้ว บังคับยุติ
return step_output
ระบบอนุญาตให้เกิดการหมดเวลาได้ 3 ครั้งโดยค่าเริ่มต้น — Agent จะได้รับการตอบกลับข้อผิดพลาดหลังจากหมดเวลาสองสามครั้งแรก ทำให้มีโอกาสเลือกคำสั่งที่เร็วกว่า เฉพาะเมื่อการหมดเวลาเกิดขึ้นติดต่อกันหลายครั้ง ระบบจะตัดสินว่า “ไม่สามารถกู้คืนได้” และยุติการโต้ตอบ กลไกนี้ช่วยเพิ่มอัตราความสำเร็จของงานระยะยาวได้อย่างมีนัยสำคัญ
unsetunsetห้า Rollout Cache: การสะสมข้อมูลการฝึกแบบเรียลไทม์unsetunset
5.1 โครงสร้างข้อมูลหลัก
Rollout Cache เป็นนวัตกรรมหลักที่ทำให้ Uni-Agent แตกต่างจากเฟรมเวิร์ก Agent อื่นๆ ทั้งหมด มันเติบโตแบบเรียลไทม์ระหว่างการโต้ตอบ โครงสร้างข้อมูลมีดังนี้:
rollout_cache = {
"request_id": "uuid-...",
"prompt_ids": [101, 2035, 8841, ...], # ลำดับ token ที่ต่อกันอย่างต่อเนื่อง
"response_mask": [0, 0, 0, ..., 1, 1, 1, ..., 0, 0, ...], # อันไหนที่โมเดลสร้าง
"response_logprobs": [0.0, 0.0, ..., -0.23, -1.1, ..., 0.0, ...],
"routed_experts": [...] | None, # ข้อมูลเส้นทาง MoE (ไม่บังคับ)
"metrics": {"generate_sequences": 1.23, ...},
"extra_fields": {"traj_masked": 0, ...},
}
ใช้ไทม์ไลน์เพื่อทำความเข้าใจบทบาทของ mask:
ลำดับ Token: [system_prompt] [user_msg] [asst_response_1] [tool_obs_1] [asst_response_2] ...
Mask: 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 ...
╰─── prompt ──╯ ╰── การตัดสินใจของโมเดล ──╯ ╰─ สภาพแวดล้อมส่งกลับ
⚠️ หมายเหตุ: เนื้อหาได้รับการแปลโดย AI และตรวจสอบโดยมนุษย์ หากมีข้อผิดพลาดโปรดแจ้ง
☕ สนับสนุนค่ากาแฟทีมงาน
หากคุณชอบบทความนี้ สามารถสนับสนุนเราได้ผ่าน PromptPay
SCAN TO PAY WITH ANY BANK
本文来自网络搜集,不代表คลื่นสร้างอนาคต立场,如有侵权,联系删除。转载请注明出处:https://www.itsolotime.com/th/archives/35466
