Đây là phần đầu tiên trong loạt bài gồm nhiều phần về cách xây dựng Đại lý bằng API Trợ lý của OpenAI bằng SDK Python. Đại lý là gì? Theo cách tôi muốn nhìn nhận, tác nhân thực sự chỉ là một phần mềm tận dụng LLM (Mô hình ngôn ngữ lớn) và cố gắng bắt chước hành vi của con người. Điều đó có nghĩa là nó không chỉ có thể trò chuyện và hiểu ngôn ngữ mà còn có thể thực hiện các hành động có tác động đến thế giới thực. Những hành động này thường được gọi là công cụ. Trong bài đăng trên blog này, chúng ta sẽ khám phá cách xây dựng một tác nhân bằng API Trợ lý của OpenAI bằng SDK Python của họ. Phần 1 sẽ chỉ là bộ xương của trợ lý. Đó là, chỉ là phần đàm thoại. Tôi đã chọn xây dựng một ứng dụng CLI nhằm mục đích không phụ thuộc vào khuôn khổ. Chúng tôi sẽ cố tình gọi việc triển khai của mình là Tác nhân và gọi việc triển khai OpenAI SDK là Trợ lý để dễ dàng phân biệt giữa hai điều này. Tôi sử dụng thuật ngữ và thay thế cho nhau khi nói đến các chức năng mà Tác nhân có thể gọi. Phần 2 sẽ trình bày chi tiết hơn về hàm callin. công cụ chức năng Điều kiện tiên quyết Để làm theo hướng dẫn này, bạn sẽ cần những điều sau: Python3 được cài đặt trên máy của bạn Khóa API OpenAI Kiến thức cơ bản về lập trình Python Khái niệm trợ lý OpenAI : Trợ lý trong API Trợ lý là một thực thể được định cấu hình để phản hồi tin nhắn của người dùng. Nó sử dụng các hướng dẫn, mô hình đã chọn và các công cụ để tương tác với các chức năng và đưa ra câu trả lời. Trợ lý : Chủ đề đại diện cho một cuộc trò chuyện hoặc cuộc đối thoại trong API Trợ lý. Nó được tạo cho mỗi tương tác của người dùng và có thể chứa nhiều Tin nhắn, đóng vai trò là nơi chứa đựng cuộc trò chuyện đang diễn ra. Chủ đề : Message là một đơn vị giao tiếp trong Thread. Nó chứa văn bản (và các tệp có thể có trong tương lai) và được sử dụng để truyền tải các truy vấn của người dùng hoặc phản hồi của trợ lý trong Chủ đề. Message : Chạy là một phiên bản Trợ lý đang xử lý một Chủ đề. Nó liên quan đến việc đọc Chủ đề, quyết định có nên gọi các công cụ hay không và tạo phản hồi dựa trên việc giải thích Thông báo của Chủ đề của mô hình. Chạy Thiết lập môi trường phát triển Bước đầu tiên là tạo môi trường ảo bằng và kích hoạt nó. Điều này sẽ đảm bảo rằng các phần phụ thuộc của chúng tôi được tách biệt khỏi quá trình cài đặt Python của hệ thống: venv python3 -m venv venv source venv/bin/activate Hãy cài đặt phần phụ thuộc duy nhất của chúng ta: gói : openai pip install openai Tạo một tệp Hãy điền một số logic thời gian chạy cơ bản cho ứng dụng CLI của chúng ta: main.py while True: user_input = input("User: ") if user_input.lower() == 'exit': print("Exiting the assistant...") break print(f"Assistant: You said {user_input}") Hãy dùng thử bằng cách chạy : python3 main.py python3 main.py User: hi Assistant: You said hi Như bạn có thể thấy, CLI chấp nhận tin nhắn của Người dùng làm đầu vào và Trợ lý thiên tài của chúng ta vẫn chưa có não 🧠 nên anh ấy chỉ lặp lại tin nhắn đó ngay lập tức. Vẫn chưa thông minh lắm. Đại lý Bây giờ, cuộc vui 😁 (hay đau đầu 🤕) bắt đầu. Tôi sẽ cung cấp tất cả nội dung nhập cần thiết cho lớp cuối cùng ngay bây giờ, để bạn không phải đắn đo xem mọi thứ đến từ đâu vì tôi đã liên tục nhập các mẫu mã để cho ngắn gọn. Hãy bắt đầu bằng cách xây dựng một lớp trong một tệp mới : Agent agent.py import time import openai from openai.types.beta.threads.run import Run class Agent: def __init__(self, name: str, personality: str): self.name = name self.personality = personality self.client = openai.OpenAI(api_key="sk-*****") self.assistant = self.client.beta.assistants.create( name=self.name, model="gpt-4-turbo-preview" ) Trong hàm tạo lớp, chúng tôi khởi tạo ứng dụng khách OpenAI làm thuộc tính lớp bằng cách chuyển khóa API OpenAI của chúng tôi. Tiếp theo, chúng tôi tạo một thuộc tính lớp ánh xạ tới Trợ lý mới tạo của chúng tôi. Chúng tôi lưu trữ và thuộc tính lớp để sử dụng sau này. assistant name personality Đối số mà chúng ta đang chuyển đến phương thức tạo chỉ nhằm mục đích xác định Trợ lý trong bảng điều khiển OpenAI và AI thực sự không biết về điều đó vào thời điểm này. Bạn thực sự phải chuyển tên cho mà chúng ta sẽ thấy sau. name instructions Bạn đã có thể đặt khi tạo Trợ lý, nhưng điều đó thực sự sẽ khiến Trợ lý của bạn kém linh hoạt hơn trước những thay đổi linh hoạt. instructions Bạn có thể cập nhật Trợ lý bằng cách gọi nhưng có một nơi tốt hơn để chuyển các giá trị động mà chúng ta sẽ thấy khi chuyển sang Chạy. client.beta.assistants.update Lưu ý rằng nếu bạn chuyển đi ở đây khi tạo Cuộc chạy, của Trợ lý sẽ bị ghi đè bằng của cuộc chạy. Chúng không bổ sung cho nhau, vì vậy hãy chọn một tùy theo nhu cầu của bạn: Cấp độ Trợ lý cho hướng dẫn tĩnh hoặc Cấp độ Chạy cho hướng dẫn động. instructions instructions instructions Đối với mô hình, tôi đã chọn mô hình để chúng ta có thể thêm chức năng gọi trong phần 2 của loạt bài này. Bạn có thể sử dụng nếu bạn muốn tiết kiệm một vài xu trong khi vẫn cảm thấy đau đầu vì thất vọng khi chúng tôi triển khai các công cụ. gpt-4-turbo-preview gpt-3.5-turbo GPT 3.5 có công cụ gọi điện rất tệ; những giờ tôi đã mất để cố gắng giải quyết nó cho phép tôi nói điều đó. 😝 Tôi sẽ để nó ở đó và nói thêm về điều này sau. Tạo chủ đề, thêm tin nhắn và truy xuất tin nhắn cuối cùng Sau khi tạo một tổng đài viên, chúng ta sẽ cần bắt đầu một chuỗi hội thoại. class Agent: # ... (rest of code) def create_thread(self): self.thread = self.client.beta.threads.create() Và chúng tôi sẽ muốn có cách thêm tin nhắn vào chuỗi đó: class Agent: # ... (rest of code) def add_message(self, message): self.client.beta.threads.messages.create( thread_id=self.thread.id, role="user", content=message ) Lưu ý rằng hiện tại, chỉ có thể thêm tin nhắn với vai trò . Tôi tin rằng OpenAI có kế hoạch thay đổi điều này trong phiên bản tương lai vì điều này khá hạn chế. user Bây giờ, chúng ta có thể nhận được tin nhắn cuối cùng trong chuỗi: class Agent: # ... (rest of code) def get_last_message(self): return self.client.beta.threads.messages.list( thread_id=self.thread.id ).data[0].content[0].text.value Tiếp theo, chúng ta tạo một phương thức điểm vào để kiểm tra những gì chúng ta có cho đến nay. Hiện tại, phương thức chỉ trả về tin nhắn cuối cùng trong chuỗi. Nó không thực sự thực hiện Chạy. Nó vẫn còn thiếu não. run_agent run_agent class Agent: # ... (rest of code) def run_agent(self): message = self.get_last_message() return message Quay lại , chúng ta tạo tác nhân và luồng đầu tiên. Chúng tôi thêm một tin nhắn vào chủ đề. Sau đó trả lại tin nhắn đó cho người dùng, nhưng lần này, đến từ chuỗi trực tiếp đó. main.py from agent import Agent agent = Agent(name="Bilbo Baggins", personality="You are the accomplished and renowned adventurer from The Hobbit. You act like you are a bit of a homebody, but you are always up for an adventure. You worry a bit too much about breakfast.") agent.create_thread() while True: user_input = input("User: ") if user_input.lower() == 'exit': print("Exiting the agent...") break agent.add_message(user_input) answer = agent.run_agent() print(f"Assistant: {answer}") Hãy chạy nó: python3 main.py User: hi Assistant: hi Vẫn chưa thông minh lắm. Gần giống một con vẹt 🦜 hơn là một người Hobbit. Trong phần tiếp theo, niềm vui thực sự bắt đầu. Tạo và bỏ phiếu cho một cuộc chạy Khi tạo một lần chạy, bạn cần truy xuất định kỳ đối tượng để kiểm tra trạng thái của lần chạy. Đây được gọi là bỏ phiếu, và nó thật tệ. Bạn cần thăm dò ý kiến để xác định xem đại lý của bạn nên làm gì tiếp theo. OpenAI có kế hoạch bổ sung hỗ trợ phát trực tuyến để làm cho việc này đơn giản hơn. Trong lúc chờ đợi, tôi sẽ hướng dẫn bạn cách thiết lập bỏ phiếu trong phần tiếp theo. Run Lưu ý trên các tên phương thức sau đây là tiêu chuẩn trong Python để chỉ ra rằng phương thức này được thiết kế để sử dụng nội bộ và không được truy cập trực tiếp bằng mã bên ngoài. _ Trước tiên, hãy tạo một phương thức trợ giúp để tạo và cập nhật để gọi phương thức này: _create_run Run run_agent class Agent: # ... (rest of code) def get_breakfast_count_from_db(self): return 1 def _create_run(self): count = self.get_breakfast_count_from_db() return self.client.beta.threads.runs.create( thread_id=self.thread.id, assistant_id=self.assistant.id, instructions=f""" Your name is: {self.name} Your personality is: {self.personality} Metadata related to this conversation: {{ "breakfast_count": {count} }} """, ) def run_agent(self): run = self._create_run() # add this line message = self.get_last_message() return message Lưu ý cách chúng tôi chuyển và để tạo một lượt chạy. thread.id assistant.id Hãy nhớ lúc đầu tôi đã nói rằng có một nơi tốt hơn để truyền các hướng dẫn và dữ liệu động? Đó sẽ là tham số khi tạo Run. Trong trường hợp của chúng tôi, chúng tôi có thể lấy bữa sáng từ cơ sở dữ liệu. Điều này sẽ cho phép bạn dễ dàng chuyển các dữ liệu động có liên quan khác nhau mỗi khi bạn muốn kích hoạt câu trả lời. instructions count Bây giờ, đại lý của bạn nhận thức được thế giới đang thay đổi xung quanh nó và có thể hành động tương ứng. Tôi muốn có một đối tượng JSON siêu dữ liệu trong hướng dẫn của mình để lưu giữ bối cảnh động có liên quan. Điều này cho phép tôi truyền dữ liệu ít dài dòng hơn và ở định dạng mà LLM thực sự hiểu rõ. Đừng chạy cái này vội; nó sẽ không hoạt động vì chúng tôi không đợi quá trình chạy hoàn tất khi chúng tôi nhận được tin nhắn cuối cùng, vì vậy nó vẫn sẽ là tin nhắn cuối cùng của người dùng. Hãy giải quyết vấn đề này bằng cách xây dựng cơ chế bỏ phiếu của chúng ta. Trước tiên, chúng ta sẽ cần một cách để truy xuất một lần chạy nhiều lần và dễ dàng, vì vậy hãy thêm phương thức : _retrieve_run class Agent: # ... (rest of code) def _retrieve_run(self, run: Run): return self.client.beta.threads.runs.retrieve( run_id=run.id, thread_id=self.thread.id) Lưu ý cách chúng ta cần chuyển cả và để tìm một lần chạy cụ thể. run.id thread.id Thêm phương thức vào lớp Agent của chúng tôi: _poll_run class Agent: # ... (rest of code) def _cancel_run(self, run: Run): self.client.beta.threads.runs.cancel( run_id=run.id, thread_id=self.thread.id) def _poll_run(self, run: Run): status = run.status start_time = time.time() while status != "completed": if status == 'failed': raise Exception(f"Run failed with error: {run.last_error}") if status == 'expired': raise Exception("Run expired.") time.sleep(1) run = self._retrieve_run(run) status = run.status elapsed_time = time.time() - start_time if elapsed_time > 120: # 2 minutes self._cancel_run(run) raise Exception("Run took longer than 2 minutes.") 🥵 Phew, nhiều lắm... Hãy giải nén nó nhé. nhận đối tượng làm đối số và trích xuất Run hiện tại. Tất cả các trạng thái sẵn có có thể được tìm thấy trong OpenAI. Chúng tôi sẽ chỉ sử dụng một số phù hợp với mục đích hiện tại của chúng tôi. _poll_run Run status tài liệu Bây giờ chúng tôi chạy vòng lặp while để kiểm tra trạng thái đã hoàn thành trong khi xử lý một số trường hợp lỗi. Việc thanh toán thực tế của API Trợ lý hơi mơ hồ, vì vậy để đảm bảo an toàn, tôi đã chọn hủy các lần chạy của mình sau 2 phút. Mặc dù có trạng thái khi OpenAI hủy chạy sau 10 phút. Nếu quá trình chạy mất hơn 2 phút thì có thể bạn đang gặp sự cố. expired Vì tôi cũng không muốn bỏ phiếu cứ sau vài mili giây nên tôi điều tiết yêu cầu của mình bằng cách chỉ bỏ phiếu mỗi 1 giây cho đến khi chạm mốc 2 phút và hủy lượt chạy của mình. Bạn có thể điều chỉnh điều này cho phù hợp. Mỗi lần lặp lại sau độ trễ, chúng tôi lại tìm nạp lại trạng thái Chạy. Bây giờ, hãy kết nối tất cả những thứ đó vào phương thức của chúng ta. Bạn sẽ nhận thấy trước tiên chúng tôi tạo cuộc chạy bằng sau đó chúng tôi thăm dò ý kiến với cho đến khi nhận được câu trả lời hoặc đưa ra lỗi và cuối cùng khi quá trình bỏ phiếu kết thúc, chúng tôi truy xuất thông báo cuối cùng từ chuỗi mà bây giờ sẽ là từ tác nhân. run_agent _create_run _poll_run Sau đó, chúng tôi đưa tin nhắn trở lại vòng lặp thời gian chạy để nó có thể được gửi lại cho người dùng. class Agent: # ... (rest of code) def run_agent(self): run = self._create_run() self._poll_run(run) # add this line message = self.get_last_message() return message Voilà, bây giờ khi bạn điều hành lại đại lý của mình, bạn sẽ nhận được phản hồi từ Đại lý thân thiện của chúng tôi: python3 main.py User: hi Assistant: Hello there! What adventure can we embark on today? Or perhaps, before we set out, we should think about breakfast. Have you had yours yet? I've had mine, of course – can't start the day without a proper breakfast, you know. User: how many breakfasts have you had? Assistant: Ah, well, I've had just 1 breakfast today. But the day is still young, and there's always room for a second, isn't there? What about you? How can I assist you on this fine day? Trong phần 2, chúng tôi sẽ bổ sung thêm khả năng cho Agent của chúng tôi gọi các công cụ. Bạn có thể tìm thấy mã đầy đủ trên của tôi. GitHub Cảm ơn bạn đã đọc. Rất vui khi được nghe bất kỳ suy nghĩ và phản hồi nào trong phần bình luận. Theo dõi tôi trên Linkedin để biết thêm nội dung như thế này: https://www.linkedin.com/in/jean-marie-dalmasso-1b5473141/