Hướng dẫn hội thảo thực hành kỹ thuật về Duet AI dành cho nhà phát triển trong lớp học lập trình

1. Mục tiêu

Mục đích của hội thảo này là nhằm phổ biến kiến thức thực tế về Duet AI cho người dùng và chuyên viên.

Trong lớp học lập trình này, bạn sẽ tìm hiểu các nội dung sau:

  1. Kích hoạt Duet AI trong dự án GCP và định cấu hình để sử dụng trong IDE và Cloud Console.
  2. Sử dụng Duet AI để tạo, hoàn thành và giải thích mã.
  3. Sử dụng Duet AI để giải thích và khắc phục sự cố về ứng dụng.
  4. Các tính năng của Duet AI như trò chuyện IDE và trò chuyện nhiều lượt, trò chuyện so với tạo mã cùng dòng, các thao tác thông minh như giải thích mã và xác nhận trích dẫn cùng nhiều tính năng khác.

Narrative

Để chứng minh cách Duet AI cho Nhà phát triển được áp dụng đúng cách trong hoạt động phát triển hằng ngày, các hoạt động của hội thảo này diễn ra theo bối cảnh nhiều câu chuyện.

Một nhà phát triển mới gia nhập một công ty thương mại điện tử. Họ có nhiệm vụ thêm dịch vụ mới vào ứng dụng thương mại điện tử hiện có (bao gồm nhiều dịch vụ). Dịch vụ mới cung cấp thêm thông tin (kích thước, trọng lượng, v.v.) về các sản phẩm trong danh mục sản phẩm. Dịch vụ này sẽ giúp bạn cải thiện chi phí vận chuyển dựa trên kích thước và trọng lượng sản phẩm.

nhà phát triển mới tham gia công ty, nên họ sẽ sử dụng Duet AI để tạo mã, nội dung giải thích và tài liệu.

Sau khi dịch vụ được mã hoá, một quản trị viên nền tảng sẽ sử dụng Duet AI (trò chuyện) để giúp tạo cấu phần phần mềm (vùng chứa Docker) và các tài nguyên cần thiết để triển khai cấu phần phần mềm cho GCP (ví dụ: Artifact Registry, quyền IAM, kho lưu trữ mã, cơ sở hạ tầng điện toán như GKE hoặc CloudRun, v.v.)

Sau khi ứng dụng được triển khai cho GCP, một nhà điều hành ứng dụng/SRE sẽ sử dụng Duet AI (và Cloud Ops) để giúp khắc phục lỗi trong dịch vụ mới.

Đối tượng sử dụng

Hội thảo bao gồm các đối tượng sau:

  1. Nhà phát triển ứng dụng – Cần có một số kiến thức về lập trình và phát triển phần mềm.

Phiên bản hội thảo này của Duet AI chỉ dành cho nhà phát triển. Bạn không cần phải có kiến thức về tài nguyên trên đám mây của GCP. Bạn có thể tìm thấy các tập lệnh về cách tạo các tài nguyên GCP cần thiết để chạy ứng dụng này tại đây. Bạn có thể làm theo các bước trong hướng dẫn này để triển khai các tài nguyên GCP bắt buộc.

2. Chuẩn bị môi trường

Kích hoạt Duet AI

Bạn có thể kích hoạt Duet AI trong một dự án GCP thông qua API (các công cụ gcloud hoặc IaC như Terraform) hoặc thông qua giao diện người dùng của Cloud Console.

Để kích hoạt Duet AI trong một dự án trên Google Cloud, bạn cần bật Cloud AI Companion API và cấp cho người dùng vai trò Quản lý danh tính và quyền truy cập (IAM) của người dùng Cloud AI Companion cũng như vai trò Quản lý danh tính và quyền truy cập (IAM) của người xem theo mức sử dụng dịch vụ.

Qua gcloud

Kích hoạt Cloud Shell:

Định cấu hình PROJECT_ID, USER và bật Cloud AI Companion API.

export PROJECT_ID=<YOUR PROJECT ID>
export USER=<YOUR USERNAME> # Use your full LDAP, e.g. name@example.com
gcloud config set project ${PROJECT_ID}
gcloud services enable cloudaicompanion.googleapis.com --project ${PROJECT_ID}

Kết quả đầu ra sẽ có dạng như sau:

Updated property [core/project].
Operation "operations/acat.p2-60565640195-f37dc7fe-b093-4451-9b12-934649e2a435" finished successfully.

Cấp cho Người dùng Cloud AI Companion và vai trò Quản lý danh tính và quyền truy cập (IAM) của người xem mức sử dụng dịch vụ cho tài khoản NGƯỜI DÙNG. Cloud Companion API bao gồm các tính năng trong cả IDE và bảng điều khiển mà chúng ta sẽ sử dụng. Quyền Trình xem mức sử dụng dịch vụ được dùng để kiểm tra nhanh trước khi bật giao diện người dùng trong bảng điều khiển (để giao diện người dùng Duet chỉ xuất hiện trong các dự án có bật API).

gcloud projects add-iam-policy-binding  ${PROJECT_ID} \
--member=user:${USER} --role=roles/cloudaicompanion.user

gcloud projects add-iam-policy-binding  ${PROJECT_ID} \
--member=user:${USER} --role=roles/serviceusage.serviceUsageViewer

Kết quả đầu ra sẽ có dạng như sau:

...
- members:
  - user:<YOUR USER ACCOUNT>
  role: roles/cloudaicompanion.user

...
- members:
  - user:<YOUR USER ACCOUNT>
  role: roles/serviceusage.serviceUsageViewer

Thông qua Cloud Console

Để bật API này, hãy truy cập vào trang Cloud AI Companion API trong bảng điều khiển Google Cloud.

Trong bộ chọn dự án, hãy chọn một dự án.

Nhấp vào Bật.

Trang sẽ cập nhật và hiển thị trạng thái Đã bật. Duet AI hiện đã có trong một dự án được chọn trên Google Cloud cho tất cả người dùng có vai trò quản lý danh tính và quyền truy cập (IAM) bắt buộc.

Để cấp các vai trò IAM bắt buộc để sử dụng Duet AI, hãy chuyển đến trang IAM.

Trong cột Chính, hãy tìm NGƯỜI DÙNG mà bạn muốn bật quyền truy cập vào Duet AI, sau đó nhấp vào biểu tượng bút chì ✏️ Chỉnh sửa đối tượng chính trong hàng đó.

Trong ngăn quyền truy cập Chỉnh sửa, hãy nhấp vào nút thêm Thêm vai trò khác.

Trong phần Chọn vai trò, hãy chọn Người dùng đồng hành Cloud AI.

Nhấp vào Add another role (Thêm vai trò khác) rồi chọn Service Usage Inspector (Người xem cách sử dụng dịch vụ).

Nhấp vào Lưu.

Thiết lập IDE

Nhà phát triển có thể chọn trong số nhiều IDE phù hợp nhất với nhu cầu của mình. Tính năng hỗ trợ lập trình Duet AI hiện có trong nhiều IDE như Visual Studio Code, JetBrains IDE (IntelliJ, PyCharm, GoLand, WebStorm, v.v.), Cloud Workstations, Cloud Shell Editor.

Trong phòng thí nghiệm này, bạn có thể sử dụng Cloud Workstations hoặc Cloud Shell Editor.

Hội thảo này sử dụng Cloud Shell Editor.

Lưu ý rằng các máy trạm trên đám mây có thể mất 20-30 phút để thiết lập.

Để sử dụng ngay lập tức, hãy dùng Cloud Shell Editor.

Mở Cloud Shell Editor bằng cách nhấp vào biểu tượng bút chì ✏️ trong thanh trình đơn trên cùng của Cloud Shell.

Cloud Shell Editor có giao diện người dùng và trải nghiệm người dùng rất giống với VSCode.

d6a6565f83576063.png

Nhấp vào Ctrl (trong Windows)/CMD (trong Mac) + , (dấu phẩy) để vào ngăn Cài đặt.

Trên thanh Tìm kiếm, hãy nhập "Duet ai".

Đảm bảo hoặc bật Cloudcode › Duet AI: BậtCloudcode › Duet AI › Đề xuất cùng dòng: Bật Auto

111b8d587330ec74.pngS

Trong Thanh trạng thái ở dưới cùng, hãy nhấp vào Mã đám mây – Đăng nhập và làm theo quy trình đăng nhập.

Nếu bạn đã đăng nhập, thanh trạng thái sẽ hiển thị Mã đám mây – Không có dự án.

Nhấp vào Cloud Code – Không có dự án nào và một ngăn thả xuống gồm các thao tác sẽ xuất hiện ở trên cùng. Nhấp vào Chọn một dự án Google Cloud.

3241a59811e3c84a.pngS

Bắt đầu nhập mã DỰ ÁN và dự án của bạn sẽ xuất hiện trong danh sách.

c5358fc837588fe.png

Chọn PROJECT_ID của bạn trong danh sách dự án.

Thanh trạng thái ở dưới cùng sẽ cập nhật để hiển thị mã dự án của bạn. Nếu không thì bạn có thể phải làm mới thẻ Cloud Shell Editor.

Nhấp vào biểu tượng Duet AI d97fc4e7b594c3af.pngtrong thanh trình đơn bên trái và cửa sổ trò chuyện của Duet AI sẽ xuất hiện. Nếu bạn thấy thông báo có nội dung Chọn dự án GCP. Nhấp và chọn lại dự án.

Giờ đây, bạn sẽ thấy cửa sổ trò chuyện của Duet AI

781f888360229ca6.pngS

3. Thiết lập cơ sở hạ tầng

d3234d237f00fdbb.png

Để chạy dịch vụ vận chuyển mới trong GCP, bạn cần có các tài nguyên sau đây trên GCP:

  1. Một thực thể Cloud SQL, có một cơ sở dữ liệu.
  2. Một cụm GKE để chạy dịch vụ trong vùng chứa.
  3. Một Artifact Registry để lưu trữ hình ảnh Docker.
  4. Kho lưu trữ nguồn trên đám mây cho mã.

Trong cửa sổ dòng lệnh Cloud Shell, hãy sao chép kho lưu trữ sau đây rồi chạy các lệnh sau để thiết lập cơ sở hạ tầng trong dự án GCP của bạn.

# Set your project
export PROJECT_ID=<INSERT_YOUR_PROJECT_ID>
gcloud config set core/project ${PROJECT_ID}

# Enable Cloudbuild and grant Cloudbuild SA owner role 
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format 'value(projectNumber)')
gcloud services enable cloudbuild.googleapis.com
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com --role roles/owner

# Clone the repo
git clone https://github.com/duetailabs/dev.git ~/duetaidev
cd ~/duetaidev

# Run Cloudbuild to create the necessary resources
gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID}

# To destroy all GCP resources, run the following
# gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID} --config=cloudbuild_destroy.yaml

4. Phát triển dịch vụ python Flask

9745ba5c70782e76.pngS

Dịch vụ mà chúng ta sẽ tạo cuối cùng sẽ bao gồm các tệp sau đây. Bạn không cần phải tạo các tệp này ngay bây giờ và sẽ tạo từng tệp một theo hướng dẫn bên dưới:

  1. package-service.yaml – Thông số API mở cho dịch vụ gói có dữ liệu như chiều cao, chiều rộng, trọng lượng và hướng dẫn xử lý đặc biệt.
  2. data_model.py – Mô hình dữ liệu cho quy cách API dịch vụ gói. Đồng thời, tạo bảng packages trong DB product_details.
  3. connect_connector.py – Kết nối CloudSQL (xác định công cụ, Phiên và ORM cơ sở)
  4. db_init.py – Tạo dữ liệu mẫu vào bảng packages.
  5. main.py – Dịch vụ Python Flask có điểm cuối GET để truy xuất thông tin chi tiết về gói từ dữ liệu packages dựa trên product_id.
  6. test.py – Kiểm thử đơn vị
  7. requirement.txt – Các yêu cầu về Python
  8. Dockerfile – Để chứa ứng dụng này

Nếu bạn gặp bất kỳ vấn đề cố định nào trong khi làm bài tập, các tệp cuối cùng đều nằm trong APPENDIX của lớp học lập trình này để tham khảo.

Ở bước trước, bạn đã tạo một Kho lưu trữ nguồn đám mây. Sao chép kho lưu trữ. Bạn sẽ tạo các tệp ứng dụng trong thư mục kho lưu trữ được sao chép.

Trong cửa sổ dòng lệnh của Cloud Shell, hãy chạy lệnh sau để sao chép kho lưu trữ.

cd ~
gcloud source repos clone shipping shipping
cd ~/shipping 

Mở thanh bên trò chuyện của Duet AI trong trình đơn bên trái của Cloud Shell Editor. Biểu tượng này có dạng 8b135a000b259175.pngS. Giờ đây, bạn có thể sử dụng Duet AI để hỗ trợ viết mã.

package-service.yaml

Khi không mở tệp nào, hãy yêu cầu Duet tạo thông số API Mở cho dịch vụ vận chuyển.

Câu lệnh 1: Tạo thông số kỹ thuật yaml OpenAPI cho dịch vụ cung cấp thông tin vận chuyển và gói hàng dựa trên mã sản phẩm dạng số. Dịch vụ phải bao gồm thông tin về chiều cao, chiều rộng, chiều sâu, trọng lượng của gói hàng và mọi hướng dẫn xử lý đặc biệt.

ba12626f491a1204.png

Có ba tuỳ chọn được liệt kê ở trên cùng bên phải của cửa sổ mã đã tạo.

Bạn có thể COPY 71194556d8061dae.png.mã và DÁN mã vào tệp.

Bạn có thể ADD df645de8c65607a.png mã vào tệp hiện đang mở trong Trình chỉnh sửa.

Hoặc bạn có thể OPEN a4c7ed6d845df343.png mã trong một tệp mới.

Nhấp vào OPEN a4c7ed6d845df343.png mã trong tệp mới.

Nhấp vào CTRL/CMD + s để lưu tệp rồi lưu trữ tệp đó trong thư mục ứng dụng bằng tên tệp có tên là package-service.yaml. Nhấp vào OK.

f6ebd5b836949366.png

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy thực hiện các thay đổi thích hợp theo cách thủ công.

Bạn cũng có thể thử nhiều câu lệnh để xem câu trả lời của Duet AI.

Đặt lại nhật ký trò chuyện trên Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

data_model.py

Tiếp theo, bạn tạo tệp python mô hình dữ liệu cho dịch vụ dựa trên thông số kỹ thuật OpenAPI.

Khi tệp package-service.yaml đang mở, hãy nhập lời nhắc sau.

Câu lệnh 1: Sử dụng ORM sqlalchemy của python để tạo một mô hình dữ liệu cho dịch vụ API này. Ngoài ra, hãy thêm một hàm riêng biệt và một điểm truy cập chính để tạo bảng cơ sở dữ liệu.

b873a6a28bd28ca1.png

Hãy cùng xem từng phần đã được tạo ra. Duet AI vẫn là một trợ lý và mặc dù có thể giúp bạn nhanh chóng viết mã, nhưng bạn vẫn nên xem xét nội dung được tạo và hiểu nội dung đó trong quá trình thực hiện.

Đầu tiên, có một lớp Class (Lớp) tên là Package thuộc loại kiểu Base xác định mô hình dữ liệu cho cơ sở dữ liệu packages như sau:

class Package(Base):
    __tablename__ = 'packages'

    id = Column(Integer, primary_key=True)
    product_id = Column(String(255))
    height = Column(Float)
    width = Column(Float)
    depth = Column(Float)
    weight = Column(Float)
    special_handling_instructions = Column(String(255))

Tiếp theo, bạn cần một hàm tạo bảng trong cơ sở dữ liệu như sau:

def create_tables(engine):
    Base.metadata.create_all(engine)

Cuối cùng, bạn cần một hàm chính chạy hàm create_tables để thực sự tạo bảng trong cơ sở dữ liệu CloudSQL, như sau:

if __name__ == '__main__':
    from sqlalchemy import create_engine

    engine = create_engine('sqlite:///shipping.db')
    create_tables(engine)

    print('Tables created successfully.')

Xin lưu ý rằng hàm main đang tạo một công cụ bằng cách sử dụng cơ sở dữ liệu sqlite cục bộ. Để sử dụng CloudSQL, bạn sẽ cần phải thay đổi dịch vụ đó. Bạn sẽ thực hiện việc đó muộn hơn một chút.

Sử dụng mã OPEN a4c7ed6d845df343.png trong quy trình công việc mới của tệp như trước đây. Lưu mã này vào tệp có tên là data_model.py (lưu ý rằng dấu gạch dưới trong tên chứ không phải dấu gạch ngang).

Đặt lại nhật ký trò chuyện trên Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

connect-connector.py

Tạo trình kết nối CloudSQL.

Khi tệp data_model.py đang mở, hãy nhập các câu lệnh sau.

Câu lệnh 1: Sử dụng thư viện Cloud-sql-python-connector, tạo một hàm Khởi chạy nhóm kết nối cho một thực thể Cloud SQL của Postgres.

ed05cb6ff85d34c5.png

Xin lưu ý rằng phản hồi này không sử dụng thư viện cloud-sql-python-connector. Bạn có thể tinh chỉnh câu lệnh để Duet có đôi chút gợi ý, bằng cách thêm thông tin cụ thể vào cùng một chuỗi trò chuyện.

Hãy sử dụng một câu lệnh khác.

Câu lệnh 2: Phải sử dụng thư viện Cloud-sql-python-connector.

d09095b44dde35bf.png

Hãy đảm bảo tệp này sử dụng thư viện cloud-sql-python-connector.

Sử dụng mã OPEN a4c7ed6d845df343.png trong quy trình công việc mới của tệp như trước đây. Lưu mã trong tệp có tên connect_conector.py. Có thể bạn sẽ phải nhập thư viện pg8000 theo cách thủ công, vui lòng xem tệp bên dưới.

Xoá nhật ký trò chuyện của Duet AI và khi tệp connect_connector.py đang mở, hãy tạo ORM DB engine, sessionmakerbase để dùng trong ứng dụng.

Lời nhắc 1: Tạo một công cụ, lớp sessionmaker và ORM cơ sở bằng phương thức connect_with_connector

6e4214b72ab13a63.pngS

Phản hồi có thể thêm engine, SessionBase vào tệp connect_connector.py.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy thực hiện các thay đổi thích hợp theo cách thủ công.

Bạn cũng có thể thử nhiều câu lệnh để xem câu trả lời mà Duet AI có thể đưa ra.

Đặt lại nhật ký trò chuyện trên Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

Đang cập nhật data_model.py

Bạn cần sử dụng công cụ mà bạn đã tạo ở bước trước (trong tệp connect_connector.py) để tạo bảng trong cơ sở dữ liệu CloudSQL.

Xoá nhật ký trò chuyện trên Duet AI. Mở tệp data_model.py. Hãy thử câu lệnh sau.

Câu lệnh 1: Trong hàm chính, hãy nhập và sử dụng công cụ từ connect_connector.py

2e768c9b6c523b9a.png.

Bạn sẽ thấy phản hồi nhập engine từ connect_connector (đối với CloudSQL). create_table sử dụng công cụ đó (thay vì DB mặc định sqlite cục bộ).

Cập nhật tệp data_model.py.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy thực hiện các thay đổi thích hợp theo cách thủ công.

Bạn cũng có thể thử nhiều câu lệnh để xem nhiều câu trả lời của Duet AI.

Đặt lại nhật ký trò chuyện trên Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

requirements.txt

Tạo một tệp requirements.txt cho ứng dụng.

Mở cả tệp connect_connector.pydata_model.py rồi nhập lời nhắc sau đây.

Câu lệnh 1: Tạo tệp yêu cầu pip cho mô hình dữ liệu và dịch vụ này

Câu lệnh 2: Tạo tệp yêu cầu về pip cho mô hình dữ liệu và dịch vụ này bằng các phiên bản mới nhất

69fae373bc5c6a18.pngS

Xác minh tên và phiên bản là chính xác. Ví dụ: trong phản hồi ở trên, cả tên và phiên bản google-cloud-sql-connecter đều không chính xác. Sửa các phiên bản theo cách thủ công và tạo một tệp requirements.txt có dạng như sau:

cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0

Trong cửa sổ dòng lệnh, hãy chạy lệnh sau:

pip3 install -r requirements.txt

Đặt lại nhật ký trò chuyện trên Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

Tạo bảng gói trong CloudSQL

Đặt các biến môi trường cho trình kết nối cơ sở dữ liệu CloudSQL.

export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)')
export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)")
export DB_USER=evolution
export DB_PASS=evolution
export DB_NAME=product_details

Bây giờ, hãy chạy data_model.py.

python data_model.py

Kết quả tương tự như sau (kiểm tra mã để xem điều gì thực sự được mong đợi):

Tables created successfully.

Kết nối với thực thể CloudSQL và kiểm tra xem cơ sở dữ liệu đã được tạo hay chưa.

gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details

Sau khi nhập mật khẩu (cũng là tiến hoá), lấy bảng.

product_details=> \dt

Kết quả sẽ tương tự như sau:

           List of relations
 Schema |   Name   | Type  |   Owner   
--------+----------+-------+-----------
 public | packages | table | evolution
(1 row)

Bạn cũng có thể kiểm tra mô hình dữ liệu và thông tin chi tiết về bảng.

product_details=> \d+ packages

Kết quả sẽ tương tự như sau:

                                                                        Table "public.packages"
            Column             |       Type        | Collation | Nullable |               Default                | Storage  | Compression | Stats target | Description 
-------------------------------+-------------------+-----------+----------+--------------------------------------+----------+-------------+--------------+-------------
 id                            | integer           |           | not null | nextval('packages_id_seq'::regclass) | plain    |             |              | 
 product_id                    | integer           |           | not null |                                      | plain    |             |              | 
 height                        | double precision  |           | not null |                                      | plain    |             |              | 
 width                         | double precision  |           | not null |                                      | plain    |             |              | 
 depth                         | double precision  |           | not null |                                      | plain    |             |              | 
 weight                        | double precision  |           | not null |                                      | plain    |             |              | 
 special_handling_instructions | character varying |           |          |                                      | extended |             |              | 
Indexes:
    "packages_pkey" PRIMARY KEY, btree (id)
Access method: heap

Nhập \q để thoát khỏi CloudSQL.

db_init.py

Tiếp theo, hãy thêm một số dữ liệu mẫu vào bảng packages.

Xoá nhật ký trò chuyện trên Duet AI. Khi tệp data_model.py đang mở, hãy thử các lời nhắc sau.

Lời nhắc 1: Tạo một hàm tạo 10 hàng gói mẫu rồi cam kết chúng vào bảng gói

Lời nhắc 2: Sử dụng phiên từ connect_connector, tạo một hàm tạo 10 hàng gói mẫu và cam kết chúng vào bảng gói

34a9cb5f04ba5c.png

Sử dụng mã OPEN a4c7ed6d845df343.png trong quy trình công việc mới của tệp như trước đây. Lưu mã trong tệp có tên db_init.py.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy thực hiện các thay đổi thích hợp theo cách thủ công.

Bạn cũng có thể thử nhiều câu lệnh để xem nhiều câu trả lời của Duet AI.

Đặt lại nhật ký trò chuyện trên Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

Tạo dữ liệu gói mẫu

Chạy db_init.py từ dòng lệnh.

python db_init.py

Kết quả sẽ tương tự như sau:

Packages created successfully.

Kết nối lại với thực thể CloudSQL và xác minh rằng dữ liệu mẫu đã được thêm vào bảng gói.

Kết nối với thực thể CloudSQL và kiểm tra xem cơ sở dữ liệu đã được tạo hay chưa.

gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details

Sau khi nhập mật khẩu (cũng là tiến hoá), lấy tất cả dữ liệu trong bảng gói.

product_details=> SELECT * FROM packages;

Kết quả sẽ tương tự như sau:

 id | product_id | height | width | depth | weight |   special_handling_instructions   
----+------------+--------+-------+-------+--------+-----------------------------------
  1 |          0 |     10 |    10 |    10 |     10 | No special handling instructions.
  2 |          1 |     10 |    10 |    10 |     10 | No special handling instructions.
  3 |          2 |     10 |    10 |    10 |     10 | No special handling instructions.
  4 |          3 |     10 |    10 |    10 |     10 | No special handling instructions.
  5 |          4 |     10 |    10 |    10 |     10 | No special handling instructions.
  6 |          5 |     10 |    10 |    10 |     10 | No special handling instructions.
  7 |          6 |     10 |    10 |    10 |     10 | No special handling instructions.
  8 |          7 |     10 |    10 |    10 |     10 | No special handling instructions.
  9 |          8 |     10 |    10 |    10 |     10 | No special handling instructions.
 10 |          9 |     10 |    10 |    10 |     10 | No special handling instructions.
(10 rows)

Nhập \q để thoát khỏi CloudSQL.

main.py

Khi các tệp data_model.py, package-service.yamlconnect_connector.py mở, hãy tạo một main.py cho ứng dụng.

Câu lệnh 1: Sử dụng thư viện bình python – tạo một phương thức triển khai sử dụng các điểm cuối http còn lại cho dịch vụ này

Câu lệnh 2: Sử dụng thư viện bình python – tạo một phương thức triển khai sử dụng các điểm cuối http còn lại cho dịch vụ này. nhập và sử dụng SessionMaker từ connect_conector.py đến dữ liệu gói.

Câu lệnh 3: Sử dụng thư viện bình python – tạo một phương thức triển khai sử dụng các điểm cuối http còn lại cho dịch vụ này. nhập và sử dụng Gói từ data_model.py và SessionMaker từ connect_conector.py đến dữ liệu gói.

Câu lệnh 4: Sử dụng thư viện bình python – tạo một phương thức triển khai sử dụng các điểm cuối http còn lại cho dịch vụ này. nhập và sử dụng Gói từ data_model.py và SessionMaker từ connect_conector.py đến dữ liệu gói. Sử dụng IP của máy chủ lưu trữ 0.0.0.0 cho app.run

6d794fc52a90e6ae.png.

Hãy cập nhật các yêu cầu đối với main.py.

Câu lệnh: Tạo tệp yêu cầu cho main.py

1cc0b318d2d4ca2f.png.

Thêm tệp này vào tệp requirements.txt. Hãy nhớ sử dụng Flask phiên bản 3.0.0.

Sử dụng mã OPEN a4c7ed6d845df343.png trong quy trình công việc mới của tệp như trước đây. Lưu mã trong tệp có tên main.py.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy thực hiện các thay đổi thích hợp theo cách thủ công.

Đặt lại nhật ký trò chuyện trên Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

5. Kiểm thử và chạy ứng dụng

Cài đặt các yêu cầu.

pip3 install -r requirements.txt

Chạy main.py.

python main.py

Kết quả sẽ tương tự như sau:

 * Serving Flask app 'main'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://10.88.0.3:5000
Press CTRL+C to quit

Trên một thiết bị đầu cuối thứ hai, hãy kiểm thử điểm cuối /packages/<product_id>.

curl localhost:5000/packages/1

Kết quả sẽ tương tự như sau:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Bạn cũng có thể thử nghiệm bất kỳ mã sản phẩm nào khác trong dữ liệu mẫu.

Nhập CTRL_C để thoát khỏi vùng chứa docker đang chạy trong dòng lệnh.

Đang tạo mã kiểm thử đơn vị

Khi tệp main.py đang mở, hãy tạo các bài kiểm thử đơn vị.

Câu lệnh 1: Tạo bài kiểm thử đơn vị.

e861e5b63e1b2657.png

Sử dụng mã OPEN a4c7ed6d845df343.png trong quy trình công việc mới của tệp như trước đây. Lưu mã trong tệp có tên test.py.

Trong hàm test_get_package, bạn phải định nghĩa product_id. Bạn có thể tự thêm.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy thực hiện các thay đổi thích hợp theo cách thủ công.

Đặt lại nhật ký trò chuyện trên Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

Chạy kiểm thử đơn vị

Chạy kiểm thử đơn vị.

python test.py

Kết quả sẽ tương tự như sau:

.
----------------------------------------------------------------------
Ran 1 test in 1.061s

OK

Đóng tất cả các tệp trong Cloud Shell Editor và xoá nhật ký trò chuyện bằng cách nhấp vào biểu tượng thùng rác 1eccfe10d6c540.pngS ở thanh trạng thái trên cùng.

tệp Docker

Tạo một Dockerfile cho ứng dụng này.

Hãy mở main.py rồi thử các câu lệnh sau.

Câu lệnh 1: Tạo một Dockerfile cho ứng dụng này.

Nhắc 2: Tạo một Dockerfile cho ứng dụng này. Sao chép tất cả các tệp vào vùng chứa.

9c473caea437a5c3.pngS

Bạn cũng cần đặt ENVARS cho INSTANCE_CONNECTION_NAME, DB_USER, DB_PASSDB_NAME. Bạn có thể thực hiện việc này theo cách thủ công. Dockerfile của bạn sẽ có dạng như sau:

FROM python:3.10-slim

WORKDIR /app

COPY . ./

RUN pip install -r requirements.txt

# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details

CMD ["python", "main.py"]

Sử dụng mã OPEN a4c7ed6d845df343.png trong quy trình công việc mới của tệp như trước đây. Lưu mã trong tệp có tên Dockerfile.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy thực hiện các thay đổi thích hợp theo cách thủ công.

Chạy ứng dụng trên máy

Khi Dockerfile mở, hãy thử lời nhắc sau.

Lời nhắc 1: Làm cách nào để chạy một vùng chứa cục bộ bằng Dockerfile này

570fd5c296ca8c83.pngS

Làm theo hướng dẫn.

# Build
docker build -t shipping .
# And run
docker run -p 5000:5000 -it shipping

Kết quả sẽ tương tự như sau:

 * Serving Flask app 'main'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://172.17.0.2:5000
Press CTRL+C to quit

Từ cửa sổ dòng lệnh thứ hai, hãy truy cập vào vùng chứa.

curl localhost:5000/packages/1

Kết quả sẽ tương tự như sau:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Ứng dụng trong vùng chứa đang hoạt động.

Nhập CTRL_C để thoát khỏi vùng chứa docker đang chạy trong dòng lệnh.

Hình ảnh vùng chứa toà nhà trong Artifact Registry

Tạo hình ảnh vùng chứa và đẩy đến Artifact Registry.

cd ~/shipping
gcloud auth configure-docker us-central1-docker.pkg.dev
docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping .
docker push us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping

Vùng chứa ứng dụng hiện đặt tại us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping và có thể triển khai cho GKE.

6. Triển khai ứng dụng cho cụm GKE

Một cụm Tự động triển khai GKE đã được tạo khi bạn xây dựng tài nguyên GCP cho hội thảo này. Kết nối với cụm GKE.

gcloud container clusters get-credentials gke1 \
    --region=us-central1

Chú thích tài khoản dịch vụ mặc định của Kubernetes bằng tài khoản dịch vụ của Google.

kubectl annotate serviceaccount default iam.gke.io/gcp-service-account=cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com

Kết quả sẽ tương tự như sau:

serviceaccount/default annotated

Chuẩn bị và áp dụng tệp k8s.yaml.

cp ~/duetaidev/k8s.yaml_tmpl ~/shipping/.
export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)')
export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)")
export IMAGE_REPO=us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping
envsubst < ~/shipping/k8s.yaml_tmpl > k8s.yaml
kubectl apply -f k8s.yaml

Kết quả sẽ tương tự như sau:

deployment.apps/shipping created
service/shipping created

Đợi cho đến khi Nhóm đang chạy và Dịch vụ được chỉ định địa chỉ IP của trình cân bằng tải bên ngoài.

kubectl get pods
kubectl get service shipping

Kết quả sẽ tương tự như sau:

# kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
shipping-f5d6f8d5-56cvk   1/1     Running   0          4m47s
shipping-f5d6f8d5-cj4vv   1/1     Running   0          4m48s
shipping-f5d6f8d5-rrdj2   1/1     Running   0          4m47s

# kubectl get service shipping
NAME       TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)        AGE
shipping   LoadBalancer   34.118.225.125   34.16.39.182   80:30076/TCP   5m41s

Đối với các cụm Tự động điều khiển GKE, hãy đợi vài giây cho đến khi tài nguyên sẵn sàng.

Truy cập dịch vụ thông qua địa chỉ EXTERNAL-IP.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1

Kết quả sẽ tương tự như sau:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

7. Tín dụng bổ sung: Khắc phục sự cố khi đăng ký

Xoá vai trò IAM của ứng dụng CloudSQL khỏi tài khoản dịch vụ cloudsqlsa. Điều này gây ra lỗi khi kết nối với cơ sở dữ liệu CloudSQL.

gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

Khởi động lại Nhóm vận chuyển.

kubectl rollout restart deployment shipping

Sau khi Nhóm khởi động lại, hãy thử truy cập lại vào dịch vụ shipping.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1 

Kết quả sẽ tương tự như sau:

...
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>

Kiểm tra Nhật ký bằng cách chuyển đến Kubernetes Engine > Khối lượng công việc

d225b1916c829167.png

Nhấp vào thẻ triển khai shipping rồi nhấp vào thẻ Logs (Nhật ký).

1d0459141483d6a7.pngS

Nhấp vào biểu tượng Xem trong trình khám phá nhật ký df8b9d19a9fe4c73.pngở bên phải thanh trạng thái. Thao tác này sẽ mở ra một cửa sổ mới có tên là Log Explorer (Trình khám phá nhật ký).

e86d1c265e176bc4.png

Nhấp vào một trong các mục lỗi Traceback, sau đó nhấp vào Giải thích mục nhập nhật ký này.

d6af045cf03008bc.png

Bạn có thể đọc phần giải thích về lỗi.

Tiếp theo, hãy để Duet AI giúp khắc phục lỗi.

Hãy thử câu lệnh sau.

Câu lệnh 1: Giúp tôi khắc phục lỗi này

9288dd6045369167.pngS

Nhập thông báo lỗi vào lời nhắc.

Lời nhắc 2: Bị cấm: Tên chính IAM đã xác thực có vẻ như không được phép gửi yêu cầu API. Xác minh "API Quản trị Cloud SQL" được bật trong dự án GCP và "Ứng dụng Cloud SQL" vai trò đã được cấp cho người gốc IAM

f1e64fbdc435d31c.png

Sau đó.

Câu lệnh 3: Làm cách nào để chỉ định vai trò Ứng dụng Cloud SQL cho một tài khoản dịch vụ của Google bằng gcloud?

bb8926b995a8875c.png

Chỉ định vai trò Ứng dụng Cloud SQL cho cloudsqlsa.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

Hãy đợi một lát và thử truy cập lại vào ứng dụng.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1

Kết quả sẽ tương tự như sau:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Bạn đã sử dụng thành công Duet AI trong tính năng Cloud Logging, Log Explorer (Trình khám phá nhật ký) và tính năng Log giải thích (Trình giải thích nhật ký) để khắc phục vấn đề này.

8. Kết luận

Xin chúc mừng! Bạn đã hoàn tất thành công lớp học lập trình này.

Trong lớp học lập trình này, bạn đã tìm hiểu các nội dung sau:

  1. Kích hoạt Duet AI trong dự án GCP và định cấu hình để sử dụng trong IDE và Cloud Console.
  2. Sử dụng Duet AI để tạo, hoàn thành và giải thích mã.
  3. Sử dụng Duet AI để giải thích và khắc phục sự cố về ứng dụng.
  4. Các tính năng của Duet AI như trò chuyện IDE và trò chuyện nhiều lượt, trò chuyện so với tạo mã cùng dòng, các thao tác thông minh như giải thích mã và xác nhận trích dẫn cùng nhiều tính năng khác.

9. Phụ lục

package-service.yaml

swagger: "2.0"
info:
 title: Shipping and Package Information API
 description: This API provides information about shipping and packages.
 version: 1.0.0
host: shipping.googleapis.com
schemes:
 - https
produces:
 - application/json
paths:
 /packages/{product_id}:
   get:
     summary: Get information about a package
     description: This method returns information about a package, including its height, width, depth, weight, and any special handling instructions.
     parameters:
       - name: product_id
         in: path
         required: true
         type: integer
         format: int64
     responses:
       "200":
         description: A successful response
         schema:
           type: object
           properties:
             height:
               type: integer
               format: int64
             width:
               type: integer
               format: int64
             depth:
               type: integer
               format: int64
             weight:
               type: integer
               format: int64
             special_handling_instructions:
               type: string
       "404":
         description: The product_id was not found

data_model.py

from sqlalchemy import Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base

from connect_connector import engine

Base = declarative_base()

class Package(Base):
    __tablename__ = 'packages'

    id = Column(Integer, primary_key=True)
    product_id = Column(Integer, nullable=False)
    height = Column(Float, nullable=False)
    width = Column(Float, nullable=False)
    depth = Column(Float, nullable=False)
    weight = Column(Float, nullable=False)
    special_handling_instructions = Column(String, nullable=True)

def create_tables():
    Base.metadata.create_all(engine)

if __name__ == '__main__':
    create_tables()

    print('Tables created successfully.')

connect_connector.py

import os

from google.cloud.sql.connector import Connector, IPTypes
import sqlalchemy

# You may need to manually import pg8000 and Base as follows
import pg8000
from sqlalchemy.ext.declarative import declarative_base


def connect_with_connector() -> sqlalchemy.engine.base.Engine:
   """Initializes a connection pool for a Cloud SQL instance of Postgres."""
   # Note: Saving credentials in environment variables is convenient, but not
   # secure - consider a more secure solution such as
   # Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
   # keep secrets safe.
   instance_connection_name = os.environ[
       "INSTANCE_CONNECTION_NAME"
   ]  # e.g. 'project:region:instance'
   db_user = os.environ["DB_USER"]  # e.g. 'my-database-user'
   db_pass = os.environ["DB_PASS"]  # e.g. 'my-database-password'
   db_name = os.environ["DB_NAME"]  # e.g. 'my-database'

   ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC

   connector = Connector()

   def getconn() -> sqlalchemy.engine.base.Engine:
       conn: sqlalchemy.engine.base.Engine = connector.connect(
           instance_connection_name,
           "pg8000",
           user=db_user,
           password=db_pass,
           db=db_name,
           ip_type=ip_type,
       )
       return conn

   pool = sqlalchemy.create_engine(
       "postgresql+pg8000://",
       creator=getconn,
       # ...
   )
   return pool

# Create a connection pool
engine = connect_with_connector()

# Create a sessionmaker class to create new sessions
SessionMaker = sqlalchemy.orm.sessionmaker(bind=engine)

# Create a Base class for ORM
# You may need to manually fix the following
Base = declarative_base()

db_init.py

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from connect_connector import engine

from data_model import Package

def create_packages():
    # Create a session
    session = sessionmaker(bind=engine)()

    # Create 10 sample packages
    for i in range(10):
        package = Package(
            product_id=i,
            height=10.0,
            width=10.0,
            depth=10.0,
            weight=10.0,
            special_handling_instructions="No special handling instructions."
        )

        # Add the package to the session
        session.add(package)

    # Commit the changes
    session.commit()

if __name__ == '__main__':
    create_packages()

    print('Packages created successfully.')

main.py

from flask import Flask, request, jsonify

from data_model import Package
from connect_connector import SessionMaker

app = Flask(__name__)

session_maker = SessionMaker()

@app.route("/packages/<int:product_id>", methods=["GET"])
def get_package(product_id):
  """Get information about a package."""

  session = session_maker

  package = session.query(Package).filter(Package.product_id == product_id).first()

  if package is None:
    return jsonify({"message": "Package not found."}), 404

  return jsonify(
      {
          "height": package.height,
          "width": package.width,
          "depth": package.depth,
          "weight": package.weight,
          "special_handling_instructions": package.special_handling_instructions,
      }
  ), 200

if __name__ == "__main__":
  app.run(host="0.0.0.0")

test.py

import unittest

from data_model import Package
from connect_connector import SessionMaker

from main import app

class TestPackage(unittest.TestCase):

    def setUp(self):
        self.session_maker = SessionMaker()

    def tearDown(self):
        self.session_maker.close()

    def test_get_package(self):
        """Test the `get_package()` function."""

        package = Package(
        product_id=11, # Ensure that the product_id different from the sample data
        height=10,
        width=10,
        depth=10,
        weight=10,
        special_handling_instructions="Fragile",
        )

        session = self.session_maker

        session.add(package)
        session.commit()

        response = app.test_client().get("/packages/11")

        self.assertEqual(response.status_code, 200)

        self.assertEqual(
            response.json,
            {
                "height": 10,
                "width": 10,
                "depth": 10,
                "weight": 10,
                "special_handling_instructions": "Fragile",
            },
        )

if __name__ == "__main__":
    unittest.main()

requirements.txt

cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
Flask==3.0.0
gunicorn==20.1.0
psycopg2-binary==2.9.3

tệp Docker

FROM python:3.10-slim

WORKDIR /app

COPY . ./

RUN pip install -r requirements.txt

# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details

CMD ["python", "main.py"]