<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: goichi harada</title>
    <description>The latest articles on DEV Community by goichi harada (@dahara1).</description>
    <link>https://dev.to/dahara1</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4019975%2Ff6699972-af2b-4506-8b91-fceeb3e58b8e.png</url>
      <title>DEV Community: goichi harada</title>
      <link>https://dev.to/dahara1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dahara1"/>
    <language>en</language>
    <item>
      <title>AI Agent Skills migrating worldcup rag app(Gemini and GCP to Qwen and Alibaba)</title>
      <dc:creator>goichi harada</dc:creator>
      <pubDate>Tue, 07 Jul 2026 18:13:53 +0000</pubDate>
      <link>https://dev.to/dahara1/ai-agent-skills-migrating-worldcup-rag-appgemini-and-gcp-to-qwen-and-alibaba-5dmg</link>
      <guid>https://dev.to/dahara1/ai-agent-skills-migrating-worldcup-rag-appgemini-and-gcp-to-qwen-and-alibaba-5dmg</guid>
      <description>&lt;h2&gt;
  
  
  Disclosure
&lt;/h2&gt;

&lt;p&gt;Submission for the &lt;a href="https://qwencloud-hackathon.devpost.com/" rel="noopener noreferrer"&gt;Global AI Hackathon Series with Qwen Cloud&lt;/a&gt; Blog Post Prize.&lt;/p&gt;

&lt;p&gt;Project: &lt;a href="https://github.com/webbigdata-jp/cloudport-agent" rel="noopener noreferrer"&gt;CloudPort Agent&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we did this
&lt;/h2&gt;

&lt;p&gt;Most AI applications today depend on one cloud, one model provider, and one set of SDK assumptions. That is convenient until it is not. &lt;/p&gt;

&lt;p&gt;If an American model API suddenly becomes unavailable, rate-limited, too expensive, or difficult to use from a certain region, a working backup matters. Not just a theoretical backup, but a second deployment that can actually run.&lt;/p&gt;

&lt;p&gt;That was the motivation behind this project. For the Qwen Cloud hackathon, we took an existing Gemini + Google Cloud application and migrated it to Qwen + Alibaba Cloud. Then we turned the migration knowledge into reusable Qwen Code skills.&lt;/p&gt;

&lt;p&gt;The result is CloudPort Agent: a small agent workflow that captures the practical migration traps we hit, so the next migration does not start from a blank page. The migrated app is SoccerScope, a multilingual RAG app for discovering popular World Cup YouTube videos from different countries. Users can search viral football videos across languages and ask the agent to turn the findings into reports, social posts, or website-style summaries.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://soccer.tubesaku.com/" rel="noopener noreferrer"&gt;Original Gemini version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qwen-soccer.tubesaku.com/" rel="noopener noreferrer"&gt;Qwen migration demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webbigdata-jp.github.io/soccerscope/" rel="noopener noreferrer"&gt;Popular video rankings and comment sentiment statistics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Qwen version is a migration demo, not a production-sized deployment. It is meant to prove that the application can run on the Qwen + Alibaba Cloud stack and to document the traps we found along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The app we migrated
&lt;/h2&gt;

&lt;p&gt;The original SoccerScope stack looked like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent framework: Google ADK&lt;/li&gt;
&lt;li&gt;LLM: Gemini&lt;/li&gt;
&lt;li&gt;RAG: MongoDB Atlas Vector Search&lt;/li&gt;
&lt;li&gt;Embeddings: &lt;code&gt;gemini-embedding-001&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tools: official MongoDB MCP server&lt;/li&gt;
&lt;li&gt;Runtime: FastAPI on Google Cloud Run&lt;/li&gt;
&lt;li&gt;Deployment: Docker container&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The target stack was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LLM: Qwen via Alibaba Cloud Model Studio / DashScope&lt;/li&gt;
&lt;li&gt;Embeddings: &lt;code&gt;text-embedding-v4&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Runtime: Alibaba Cloud Function Compute 3.0&lt;/li&gt;
&lt;li&gt;Deployment: Function Compute custom runtime&lt;/li&gt;
&lt;li&gt;Agent assistant: Qwen Code with custom skills&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first glance, this looked like a relatively easy model swap. Because the app used Google ADK, I expected the model replacement to be mostly configuration and API mapping. In practice, the migration was easier than rewriting the whole app, but it still had several nonobvious traps. Here are the six that mattered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trap 1: Account Type
&lt;/h2&gt;

&lt;p&gt;Since the contest was hosted on Qwen Cloud, I initially created an account there. While Qwen Cloud uses email-based authentication, Alibaba Cloud relies on password-based authentication, so I reconfigured my account on Alibaba Cloud. I followed the recommendation to create a corporate account, but please be aware that verification procedures and free credit allowances can differ between corporate and individual accounts.&lt;/p&gt;

&lt;p&gt;Since the original application was designed for Cloud Run (Docker), App Engine Service seemed like a suitable choice; however, we opted for Function Compute, which has a proven track record. Although Alibaba Cloud Function Compute supports container execution, the issue was that our specific account type did not allow for a trial period, effectively mandating a production-ready setup. Consequently, we switched to an approach that utilizes the Function Compute 3.0 custom runtime instead of containers (Docker).&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Package the Python app as a zip&lt;/li&gt;
&lt;li&gt;Upload the code package&lt;/li&gt;
&lt;li&gt;Configure the startup command, such as &lt;code&gt;python3 main.py&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Expose the expected port&lt;/li&gt;
&lt;li&gt;Tune the timeout&lt;/li&gt;
&lt;li&gt;Handle runtime dependencies yourself&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was the first important lesson: a cloud migration agent should not blindly assume that "serverless app" means "container app." The right deployment path depends on the account, the region, the billing setup, and the trial constraints. CloudPort Agent now treats deployment strategy as a decision point instead of hard-coding Docker as the default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trap 2: Region choice affects custom domains
&lt;/h2&gt;

&lt;p&gt;We first tried a mainland China region. That immediately created a custom-domain issue. In mainland China regions, binding a custom domain can require ICP filing. For many overseas developers, that is not a realistic quick-start path. The temporary Function Compute URL also was not a good public demo URL for a browser-based web app. In our case, the default URL behavior was not what we wanted for a normal website demo.&lt;/p&gt;

&lt;p&gt;The fix was to recreate the deployment in the Tokyo region and use a normal custom-domain setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Host DNS in Cloudflare&lt;/li&gt;
&lt;li&gt;Point a subdomain to the Function Compute endpoint&lt;/li&gt;
&lt;li&gt;Configure the custom domain and HTTPS certificate on the Function Compute side&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The migration lesson is simple: choose your region before building everything else. For an agent, this needs to be encoded as a preflight question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this deployment meant to be a public web app with a custom domain?&lt;br&gt;&lt;br&gt;
If yes, region and domain constraints should be checked before writing deployment files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Trap 3: MCP depends on Node, and Custom Runtime did not have it
&lt;/h2&gt;

&lt;p&gt;SoccerScope uses the official MongoDB MCP server. In the original Docker environment, this was easy because Node.js was already available inside the container. The app could call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx mongodb-mcp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Function Compute Custom Runtime, that assumption failed.&lt;br&gt;
There was no Node.js binary on the expected &lt;code&gt;PATH&lt;/code&gt;. Even worse, using &lt;code&gt;npx&lt;/code&gt; at cold start meant the runtime might try to resolve packages over the network during startup. That is fragile in serverless.&lt;/p&gt;

&lt;p&gt;For a while, we removed MCP entirely and fell back to direct &lt;code&gt;pymongo&lt;/code&gt; calls. That worked, but it was not a real migration of the original architecture.&lt;/p&gt;

&lt;p&gt;The final fix was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add Node.js through Function Compute Layers.&lt;/li&gt;
&lt;li&gt;Bundle &lt;code&gt;node_modules&lt;/code&gt; during build time.&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;npx mongodb-mcp-server&lt;/code&gt; with a direct &lt;code&gt;node&lt;/code&gt; invocation.&lt;/li&gt;
&lt;li&gt;Avoid network package resolution during cold start.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the kind of trap that documentation rarely teaches in one place. Each component is documented somewhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function Compute Custom Runtime&lt;/li&gt;
&lt;li&gt;Function Compute Layers&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;MCP&lt;/li&gt;
&lt;li&gt;MongoDB MCP server&lt;/li&gt;
&lt;li&gt;Serverless cold starts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the failure only appears when you combine all of them.&lt;br&gt;
That combination is exactly what an agent skill should remember.&lt;/p&gt;
&lt;h2&gt;
  
  
  Trap 4: Gemini structured output and Qwen structured output are not identical
&lt;/h2&gt;

&lt;p&gt;Gemini made structured output feel simple. In the original app, we could pass a Pydantic-style response schema and expect the API to follow it closely.&lt;/p&gt;

&lt;p&gt;When moving to Qwen via an OpenAI-compatible API, the behavior was different. The most important lesson was not "Qwen cannot do structured output." It can. The lesson was:&lt;br&gt;
Do not assume Gemini-style schema behavior will map one-to-one to Qwen. In our migration path, we used JSON output mode and then validated locally with Pydantic.&lt;/p&gt;

&lt;p&gt;That exposed several practical issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The prompt must explicitly say that the model should output JSON. &lt;/li&gt;
&lt;li&gt;Thinking mode and JSON output settings need to be handled carefully.&lt;/li&gt;
&lt;li&gt;Truncated output can break JSON, so token limits need extra care.&lt;/li&gt;
&lt;li&gt;The expected schema should be written directly in the prompt.&lt;/li&gt;
&lt;li&gt;The application should validate the result locally and retry on mismatch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the replacement pattern became:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Put the JSON schema requirements in the prompt.&lt;/li&gt;
&lt;li&gt;Ask for JSON explicitly.&lt;/li&gt;
&lt;li&gt;Disable thinking where it conflicts with structured output.&lt;/li&gt;
&lt;li&gt;Parse the response.&lt;/li&gt;
&lt;li&gt;Validate with Pydantic.&lt;/li&gt;
&lt;li&gt;Retry if validation fails.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is boring, but it is robust. CloudPort Agent records this as an API mapping rule rather than leaving the next developer to rediscover it by reading scattered examples.&lt;/p&gt;
&lt;h2&gt;
  
  
  Trap 5: Embedding migration is not just a model-name change
&lt;/h2&gt;

&lt;p&gt;For RAG, changing the LLM is only half the migration. The embedding model matters just as much. The original app used &lt;code&gt;gemini-embedding-001&lt;/code&gt;. The Qwen version uses &lt;code&gt;text-embedding-v4&lt;/code&gt;. Those vectors are not interchangeable.&lt;/p&gt;

&lt;p&gt;That means the migration must include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Re-embedding the corpus&lt;/li&gt;
&lt;li&gt;Checking vector dimensions&lt;/li&gt;
&lt;li&gt;Checking MongoDB Atlas Vector Search index settings&lt;/li&gt;
&lt;li&gt;Preserving input order&lt;/li&gt;
&lt;li&gt;Preserving normalization behavior&lt;/li&gt;
&lt;li&gt;Validating multilingual retrieval quality after the change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case, we used 768-dimensional embeddings. But the important rule is: verify the dimension, do not assume it.&lt;/p&gt;

&lt;p&gt;There was also a smaller but very practical API difference.&lt;br&gt;
The original Gemini embedding flow used a larger chunk size. For Qwen &lt;code&gt;text-embedding-v4&lt;/code&gt;, the official batch size limit is 10 texts per request. So the migration had to change the embedding chunk size to 10.&lt;/p&gt;

&lt;p&gt;That is not a difficult change. The problem is that someone has to notice it. This is why CloudPort Agent includes examples such as &lt;code&gt;skills/gemini-to-qwen-api-mapping/examples.md&lt;/code&gt;.&lt;br&gt;
The goal is not to make humans memorize every API difference. The goal is to put those small differences into a skill file so the agent can apply them consistently.&lt;/p&gt;
&lt;h2&gt;
  
  
  Trap 6: The app you migrated may still be calling Gemini
&lt;/h2&gt;

&lt;p&gt;This was the funniest bug and the most embarrassing one.&lt;/p&gt;

&lt;p&gt;The Alibaba Cloud deployment succeeded. The web app loaded. The backend was running. Then we ran a search and saw an error like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generation failed: agent error: No API key was provided.
Please pass a valid API key.
Learn how to create an API key at https://ai.google.dev/...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app was deployed on Alibaba Cloud, but one remaining code path was still trying to call Gemini. This is where "migration" becomes a dangerous word. &lt;/p&gt;

&lt;p&gt;A migration is not complete just because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The app starts&lt;/li&gt;
&lt;li&gt;The UI loads&lt;/li&gt;
&lt;li&gt;The new API key is configured&lt;/li&gt;
&lt;li&gt;Most files were edited&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You need an end-to-end smoke test that confirms the actual runtime path. There is one important nuance here.&lt;br&gt;
Because the app uses Google ADK, we cannot say that every Google-related dependency disappeared. &lt;/p&gt;

&lt;p&gt;Google ADK itself uses Google's newer &lt;code&gt;google-genai&lt;/code&gt; SDK internally. The goal of this migration was not to delete every package with "google" in its name. The goal was to make sure that runtime LLM calls and embedding calls were routed to Qwen / DashScope where intended.&lt;/p&gt;

&lt;p&gt;CloudPort Agent now includes verification checks for this kind of hidden coupling. It does not declare success until the migrated app can run a real end-to-end request.&lt;/p&gt;
&lt;h2&gt;
  
  
  From three days to five minutes
&lt;/h2&gt;

&lt;p&gt;The first manual migration took about three days. After encoding the lessons into Qwen Code skills, the demo migration flow became much shorter.&lt;br&gt;
Measured on this project:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Manual migration&lt;/th&gt;
&lt;th&gt;CloudPort Agent demo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;About 3 days&lt;/td&gt;
&lt;td&gt;About 5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Human approvals&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Many small decisions&lt;/td&gt;
&lt;td&gt;8 approval gates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;File edits in the demo scope&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual edits across the repo&lt;/td&gt;
&lt;td&gt;2 file edits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Result&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Running Qwen migration demo&lt;/td&gt;
&lt;td&gt;Reproducible migration workflow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The point is not that every cloud migration in the world now takes five minutes. The point is that repeated migration knowledge can be captured.&lt;/p&gt;

&lt;p&gt;A human still approves important changes. The agent does the mechanical work, applies known API mappings, and checks for common failure patterns. That is the part I find interesting.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Qwen Code Skills were a good fit
&lt;/h2&gt;

&lt;p&gt;CloudPort Agent is implemented as Qwen Code custom skills.&lt;br&gt;
A skill is not magic. In practice, it is mostly structured text: instructions, rules, examples, and known traps written in a way the coding agent can use. That simplicity is useful.&lt;/p&gt;

&lt;p&gt;The migration knowledge is not locked inside a private service or a complicated framework. It lives in Markdown files. In theory, the same knowledge could also be adapted for Claude Code or other coding agents, although I have not tested that yet.&lt;br&gt;
For this project, the useful part was not just "use an agent." The useful part was:&lt;br&gt;
Put the migration scar tissue into files the agent can read.&lt;/p&gt;
&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;CloudPort Agent is available here:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/webbigdata-jp/cloudport-agent" rel="noopener noreferrer"&gt;https://github.com/webbigdata-jp/cloudport-agent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The demo prompt is here:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/webbigdata-jp/cloudport-agent/blob/main/docs/demo-prompt.md" rel="noopener noreferrer"&gt;https://github.com/webbigdata-jp/cloudport-agent/blob/main/docs/demo-prompt.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The YouTube demo is here:  &lt;/p&gt;



&lt;p&gt;If you want to try it with Qwen Code on macOS, here is the basic setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;qwen-dir
&lt;span class="nb"&gt;cd &lt;/span&gt;qwen-dir
node &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If Node.js is missing, or if your version is too old:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;node@22
brew &lt;span class="nb"&gt;link&lt;/span&gt; &lt;span class="nt"&gt;--overwrite&lt;/span&gt; &lt;span class="nt"&gt;--force&lt;/span&gt; node@22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Qwen Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;qwen-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create an Alibaba Cloud account and get an API key. Please check the latest official Alibaba Cloud / Qwen Code documentation for the current authentication steps.&lt;br&gt;
At the time of writing, the Singapore region has useful free quota options, so it is a good place to start.&lt;/p&gt;

&lt;p&gt;Copy CloudPort Agent's skills into your current directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/webbigdata-jp/cloudport-agent /tmp/cloudport-agent
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .qwen
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; /tmp/cloudport-agent/.qwen/skills .qwen/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start Qwen Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qwen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then try a prompt based on:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/webbigdata-jp/cloudport-agent/blob/main/docs/demo-prompt.md" rel="noopener noreferrer"&gt;https://github.com/webbigdata-jp/cloudport-agent/blob/main/docs/demo-prompt.md&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;This project started as a simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can we make a real Gemini + Google Cloud app run on Qwen + Alibaba Cloud?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer was yes.&lt;br&gt;
But the more useful result was not the migrated demo site itself. It was the list of small, annoying, migration-specific details that had to be solved along the way.&lt;/p&gt;

&lt;p&gt;Docker assumptions. Region assumptions. MCP runtime assumptions. Structured output assumptions.&lt;br&gt;
Embedding batch limits. Hidden Gemini call paths.&lt;/p&gt;

&lt;p&gt;Each one is small. Together, they are why real migrations take days. CloudPort Agent is our attempt to turn those small failures into reusable agent skills.&lt;/p&gt;

&lt;p&gt;That feels like the right direction for cloud migration: not bigger documentation, but executable memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Acknowledgment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.qwencloud.com/" rel="noopener noreferrer"&gt;Qwen cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.alibabacloud.com/" rel="noopener noreferrer"&gt;Alibaba cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gemini.google.com/" rel="noopener noreferrer"&gt;google gemini&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud Platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Data provided by &lt;a href="https://tubesaku.com/" rel="noopener noreferrer"&gt;YouTube analytics tool site TubeSaku&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>qwen</category>
      <category>gemini</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
